aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorAndreas Blaesius <skate4life@gmx.de>2016-05-05 13:50:13 +0200
committerAndreas Blaesius <skate4life@gmx.de>2016-05-05 14:11:40 +0200
commit71eb4db060a0b5ab35372886a792f41cce53b866 (patch)
treeeb3acabd5d2389ef95142f8fbef3affed5bfc627 /arch
parentcb882a014352e9c57493ba29c93dbdee57f7b663 (diff)
downloadkernel_samsung_espresso10-71eb4db060a0b5ab35372886a792f41cce53b866.zip
kernel_samsung_espresso10-71eb4db060a0b5ab35372886a792f41cce53b866.tar.gz
kernel_samsung_espresso10-71eb4db060a0b5ab35372886a792f41cce53b866.tar.bz2
ARM: OMAP4: add Espresso support
Based on the sources from GT-P3110_JB_Opensource, plus a lot of cleanups and commonisation: * 7376125 sec: remove sec_debug * 5bbd0ed espresso10: remove support for chinese espresso variants * 2268c59 [WIP] Unify espresso/espresso10 * f4fc754 Unify espresso/espresso10: connector * e5b79a5 Unify espresso/espresso10: main board file, board detection functions * 33ebb62 espresso: bluetooth: cleanup * e9d2f3d board-espresso-connector.c: add missing espresso10 check * 294e783 espresso: rename espresso_is_espresso10 to board_is_espresso10 * c10890e board-espresso-connector.c: remove broken mhl gpios part * 696751c Remove unnecessary CONFIG_USB_HOST_NOTIFY * 3531c0b espresso: fix sec_muxtbl_init for p5113 variants * 085506f espresso: connector: remove usage of omap_muxtbl * 1bbf98c Remove SII9234 support * ab7e412 Rename SND_OMAP_SOC_WM8994 to SND_OMAP_SOC_ESPRESSO * c839206 espresso: round to closest valid pixel clocks * a8145af panel-ltn: commonize ltn070nl01 and ltn101al03 * 10b9598 espresso: display: update clock settings on init * acceb03 espresso: display: cleanup * d4baea7 espresso: emif: don't duplicate jedec timings * dcb93bd Unify espresso/espresso10: input * 5d5b22d espresso: input: get rid of omap_muxtbl, minor cleanups * b9b6413 Input and sensors layouts for landscape screen orientation * 6d9d26b espresso: irled: remove usage of omap_muxtbl, minor cleanups * a719b1b sec_jack: remove factory test stuff * 3042e05 espresso: switch to twl6030 gpadc * ce44fbe espresso: jack: remove usage of omap_muxtbl * 1d546e4 drivers: modem_if_v2: cleanup * a741bd5 espresso: modem: get rid of omap_muxtbl * 30f92e1 espresso: clean up PMIC board files * 5e3bc1c Unify espresso/espresso10: pmic * 5d02a5e espresso: pmic: fix annoying warnings * f241f28 espresso: pmic: update configuration * fd09f20 ASoC: wm8994: move SND_USE_SUB_MIC compile-time define to pdata * fc5d5a3 espresso: register fixed voltage regulator for mmc1 * 03b338e espresso: pmic: remove omap_muxtbl, minor cleanups * 63594e6 ASoC: omap_wm8994: get rid of omap_muxtbl, not so minor cleanups * 2709b8d espresso: pmic: fix twl6030_power_init on espresso10 * e1a5679 power: max17042_battery: move current range and sdi compensation to pdata * 41cd8c1 espresso: move bootmode setup to board files * e1b8004 espresso: power: remove usage of omap_muxtbl, cleanup * 0672d8d espresso: sdio: cleanup * b34632e Unify espresso/espresso10: sensors * 43ff628 espresso: set sensor orientations via pdata * 754db03 espresso: Update sensor board * f25245b espresso: sensors: get rid of omap_muxtbl, minor cleanups * 3a4cda1 espresso: serial: don't try to register i2c.8 on non-bby variants * f2eed54 espresso: serial: get rid of omap_muxtbl, minor cleanups * 0878522 espresso: vibrator: get rid of omap_muxtbl * 1a28ee3 espresso: update wifi setup * 4456fba espresso: wifi: get rid of omap_muxtbl
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/mach-omap2/Kconfig9
-rw-r--r--arch/arm/mach-omap2/Makefile20
-rw-r--r--arch/arm/mach-omap2/board-espresso-bluetooth.c332
-rw-r--r--arch/arm/mach-omap2/board-espresso-connector.c1156
-rw-r--r--arch/arm/mach-omap2/board-espresso-display.c195
-rw-r--r--arch/arm/mach-omap2/board-espresso-emif.c48
-rw-r--r--arch/arm/mach-omap2/board-espresso-input.c295
-rw-r--r--arch/arm/mach-omap2/board-espresso-irled.c320
-rw-r--r--arch/arm/mach-omap2/board-espresso-jack.c178
-rw-r--r--arch/arm/mach-omap2/board-espresso-modems.c285
-rw-r--r--arch/arm/mach-omap2/board-espresso-pmic.c617
-rw-r--r--arch/arm/mach-omap2/board-espresso-power.c464
-rw-r--r--arch/arm/mach-omap2/board-espresso-sdio.c102
-rw-r--r--arch/arm/mach-omap2/board-espresso-sensors.c230
-rw-r--r--arch/arm/mach-omap2/board-espresso-serial.c292
-rw-r--r--arch/arm/mach-omap2/board-espresso-vibrator.c154
-rw-r--r--arch/arm/mach-omap2/board-espresso-wifi.c387
-rw-r--r--arch/arm/mach-omap2/board-espresso.c482
-rw-r--r--arch/arm/mach-omap2/board-espresso.h94
19 files changed, 5660 insertions, 0 deletions
diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig
index 7bb61c5..f947cd7 100644
--- a/arch/arm/mach-omap2/Kconfig
+++ b/arch/arm/mach-omap2/Kconfig
@@ -372,6 +372,15 @@ config MACH_OMAP4_PANDA
select OMAP_REBOOT_REASON
select OMAP_RAM_CONSOLE
+config MACH_OMAP4_ESPRESSO
+ bool "Samsung Espresso / Espresso10 (Galaxy Tab 2) Board"
+ depends on ARCH_OMAP4
+ default n
+ select OMAP_PACKAGE_CBS
+ select OMAP_RAM_CONSOLE
+ select REGULATOR_FIXED_VOLTAGE
+ select TWL6030_GPADC
+
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 3e1b519..ab5a215 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -304,6 +304,26 @@ obj-$(CONFIG_MACH_CRANEBOARD) += board-am3517crane.o
obj-$(CONFIG_MACH_SBC3530) += board-omap3stalker.o \
hsmmc.o
obj-$(CONFIG_MACH_TI8168EVM) += board-ti8168evm.o
+
+obj-$(CONFIG_MACH_OMAP4_ESPRESSO) += hsmmc.o \
+ omap_phy_internal.o \
+ board-espresso.o \
+ board-espresso-emif.o \
+ board-espresso-serial.o \
+ board-espresso-pmic.o \
+ board-espresso-sdio.o \
+ board-espresso-connector.o \
+ board-espresso-display.o \
+ board-espresso-input.o \
+ board-espresso-wifi.o \
+ board-espresso-modems.o \
+ board-espresso-sensors.o \
+ board-espresso-bluetooth.o \
+ board-espresso-jack.o \
+ board-espresso-power.o \
+ board-espresso-vibrator.o \
+ board-espresso-irled.o
+
# Platform specific device init code
usbfs-$(CONFIG_ARCH_OMAP_OTG) := usb-fs.o
obj-y += $(usbfs-m) $(usbfs-y)
diff --git a/arch/arm/mach-omap2/board-espresso-bluetooth.c b/arch/arm/mach-omap2/board-espresso-bluetooth.c
new file mode 100644
index 0000000..9e67c87
--- /dev/null
+++ b/arch/arm/mach-omap2/board-espresso-bluetooth.c
@@ -0,0 +1,332 @@
+/*
+ * 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
+ *
+ */
+
+#include <asm/mach-types.h>
+#include <linux/gpio.h>
+#include <linux/hrtimer.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/rfkill.h>
+#include <linux/serial_core.h>
+#include <linux/wakelock.h>
+#include <linux/delay.h>
+
+#include <plat/serial.h>
+
+#define GPIO_BT_EN 103
+#define GPIO_BT_NRST 82
+#define GPIO_BT_WAKE 93
+#define GPIO_BT_HOST_WAKE 83
+
+static struct rfkill *bt_rfkill;
+static bool host_wake_uart_enabled;
+static bool wake_uart_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 struct gpio bt_gpios[] = {
+ {
+ .flags = GPIOF_OUT_INIT_LOW,
+ .label = "BT_EN",
+ .gpio = GPIO_BT_EN,
+ },
+ {
+ .flags = GPIOF_OUT_INIT_LOW,
+ .label = "BT_nRST",
+ .gpio = GPIO_BT_NRST,
+ },
+ {
+ .flags = GPIOF_OUT_INIT_LOW,
+ .label = "BT_WAKE",
+ .gpio = GPIO_BT_WAKE,
+ },
+ {
+ .flags = GPIOF_IN,
+ .label = "BT_HOST_WAKE",
+ .gpio = GPIO_BT_HOST_WAKE,
+ },
+};
+
+static int bcm4330_bt_rfkill_set_power(void *data, bool blocked)
+{
+ /* rfkill_ops callback. Turn transmitter on when blocked is false */
+ if (!blocked) {
+ pr_info("[BT] Bluetooth Power On.\n");
+ gpio_set_value(GPIO_BT_EN, 1);
+ msleep(100);
+ gpio_set_value(GPIO_BT_NRST, 1);
+ msleep(50);
+
+ } else {
+ pr_info("[BT] Bluetooth Power Off.\n");
+ gpio_set_value(GPIO_BT_NRST, 0);
+ gpio_set_value(GPIO_BT_EN, 0);
+ }
+
+ 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);
+
+ if (!wake_uart_enabled && wake)
+ omap_uart_enable(2);
+
+ gpio_set_value(GPIO_BT_WAKE, wake);
+
+ if (wake_uart_enabled && !wake)
+ omap_uart_disable(2);
+
+ wake_uart_enabled = 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);
+ if (!host_wake_uart_enabled)
+ omap_uart_enable(2);
+ } else {
+ if (host_wake_uart_enabled)
+ omap_uart_disable(2);
+ /* 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);
+ }
+
+ host_wake_uart_enabled = host_wake;
+}
+
+static irqreturn_t host_wake_isr(int irq, void *dev)
+{
+ int host_wake;
+ unsigned long flags;
+
+ host_wake = gpio_get_value(GPIO_BT_HOST_WAKE);
+ 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;
+
+ 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);
+ 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(GPIO_BT_HOST_WAKE);
+ ret = request_irq(irq, host_wake_isr, IRQF_TRIGGER_HIGH,
+ "bt host_wake", NULL);
+ if (ret) {
+ gpio_free(GPIO_BT_WAKE);
+ gpio_free(GPIO_BT_HOST_WAKE);
+ return ret;
+ }
+
+ ret = irq_set_irq_wake(irq, 1);
+ if (ret) {
+ gpio_free(GPIO_BT_WAKE);
+ gpio_free(GPIO_BT_HOST_WAKE);
+ return ret;
+ }
+
+ gpio_direction_output(GPIO_BT_WAKE, 0);
+ gpio_direction_input(GPIO_BT_HOST_WAKE);
+
+ return 0;
+}
+
+static int bcm4330_bluetooth_probe(struct platform_device *pdev)
+{
+ int rc = 0;
+ int ret = 0;
+
+ gpio_request_array(bt_gpios, ARRAY_SIZE(bt_gpios));
+
+ gpio_direction_output(GPIO_BT_EN, 0);
+ gpio_direction_output(GPIO_BT_NRST, 0);
+
+ bt_rfkill = rfkill_alloc("bcm4330 Bluetooth", &pdev->dev,
+ RFKILL_TYPE_BLUETOOTH, &bcm4330_bt_rfkill_ops,
+ NULL);
+
+ if (unlikely(!bt_rfkill)) {
+ gpio_free(GPIO_BT_NRST);
+ gpio_free(GPIO_BT_EN);
+ return -ENOMEM;
+ }
+
+ rfkill_init_sw_state(bt_rfkill, 0);
+
+ rc = rfkill_register(bt_rfkill);
+
+ if (unlikely(rc)) {
+ rfkill_destroy(bt_rfkill);
+ gpio_free(GPIO_BT_NRST);
+ gpio_free(GPIO_BT_EN);
+ return -1;
+ }
+
+ rfkill_set_sw_state(bt_rfkill, true);
+
+ ret = bcm_bt_lpm_init(pdev);
+ if (ret) {
+ rfkill_unregister(bt_rfkill);
+ rfkill_destroy(bt_rfkill);
+
+ gpio_free(GPIO_BT_NRST);
+ gpio_free(GPIO_BT_EN);
+ }
+
+ return ret;
+}
+
+static int bcm4330_bluetooth_remove(struct platform_device *pdev)
+{
+ rfkill_unregister(bt_rfkill);
+ rfkill_destroy(bt_rfkill);
+
+ gpio_free_array(bt_gpios, ARRAY_SIZE(bt_gpios));
+
+ wake_lock_destroy(&bt_lpm.wake_lock);
+ return 0;
+}
+
+int bcm4430_bluetooth_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ int irq = gpio_to_irq(GPIO_BT_HOST_WAKE);
+ int host_wake;
+
+ disable_irq(irq);
+ host_wake = gpio_get_value(GPIO_BT_HOST_WAKE);
+
+ if (host_wake) {
+ enable_irq(irq);
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+int bcm4430_bluetooth_resume(struct platform_device *pdev)
+{
+ int irq = gpio_to_irq(GPIO_BT_HOST_WAKE);
+ enable_irq(irq);
+ 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)
+{
+ return platform_driver_register(&bcm4330_bluetooth_platform_driver);
+}
+module_init(bcm4330_bluetooth_init);
+
+static void __exit bcm4330_bluetooth_exit(void)
+{
+ platform_driver_unregister(&bcm4330_bluetooth_platform_driver);
+}
+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-espresso-connector.c b/arch/arm/mach-omap2/board-espresso-connector.c
new file mode 100644
index 0000000..16d0b40
--- /dev/null
+++ b/arch/arm/mach-omap2/board-espresso-connector.c
@@ -0,0 +1,1156 @@
+/* arch/arm/mach-omap2/board-espresso-connector.c
+ *
+ * Copyright (C) 2011 Samsung Electronics Co, Ltd.
+ *
+ * Based on mach-omap2/board-tuna-connector.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/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/regulator/consumer.h>
+#include <linux/usb/otg.h>
+#include <linux/delay.h>
+#include <linux/i2c/twl.h>
+#include <linux/mutex.h>
+#include <linux/switch.h>
+#include <linux/30pin_con.h>
+#include <linux/mfd/stmpe811.h>
+#include <linux/sec_dock_keyboard.h>
+#include <linux/battery.h>
+#include <linux/bat_manager.h>
+#include <linux/irq.h>
+
+#include <plat/usb.h>
+
+#include "board-espresso.h"
+#include "mux.h"
+
+#define GPIO_TA_NCONNECTED 32
+
+#define CHARGERUSB_CTRL1 0x8
+#define CHARGERUSB_CTRL3 0xA
+#define CHARGERUSB_CINLIMIT 0xE
+
+#define ESPRESSO_MANUAL_USB_NONE 0
+#define ESPRESSO_MANUAL_USB_MODEM 1
+#define ESPRESSO_MANUAL_USB_AP 2
+
+#define ESPRESSO_MANUAL_UART_NONE 0
+#define ESPRESSO_MANUAL_UART_MODEM 1
+#define ESPRESSO_MANUAL_UART_AP 2
+
+#define IF_UART_SEL_CP 0
+#define IF_UART_SEL_AP 1
+
+#define ADC_CHANNEL_IN0 4
+#define ADC_CHANNEL_IN1 5
+#define ADC_CHANNEL_IN2 6
+#define ADC_CHANNEL_IN3 7
+
+#define MAX_ADC_VAL 4096
+#define MIN_ADC_VAL 0
+
+#define MASK_SWITCH_USB_AP 0x01
+#define MASK_SWITCH_UART_AP 0x02
+
+static char *device_names[] = {
+ [P30_OTG] = "otg",
+ [P30_EARJACK_WITH_DOCK] = "earjack",
+ [P30_CARDOCK] = "car-dock",
+ [P30_ANAL_TV_OUT] = "TV-Outline",
+ [P30_KEYBOARDDOCK] = "keboard-dock",
+ [P30_DESKDOCK] = "desk-dock",
+ [P30_JIG] = "jig",
+ [P30_USB] = "USB",
+ [P30_TA] = "TA",
+};
+
+struct omap4_otg {
+ struct otg_transceiver otg;
+ struct device dev;
+
+ struct regulator *vusb;
+ struct work_struct set_vbus_work;
+ struct mutex lock;
+
+ bool reg_on;
+ bool need_vbus_drive;
+ int usb_manual_mode;
+ int uart_manual_mode;
+ int current_device;
+
+ struct switch_dev dock_switch;
+ struct switch_dev audio_switch;
+};
+
+static struct omap4_otg espresso_otg_xceiv;
+
+static struct device *sec_switch_dev;
+static int init_switch_sel;
+
+enum {
+ UEVENT_DOCK_NONE = 0,
+ UEVENT_DOCK_DESK,
+ UEVENT_DOCK_CAR,
+ UEVENT_DOCK_KEYBOARD = 9,
+};
+
+enum {
+ UEVENT_EARJACK_DETACHED = 0,
+ UEVENT_EARJACK_ATTACHED,
+};
+
+enum {
+ GPIO_ACCESSORY_EN = 0,
+ GPIO_ACCESSORY_INT,
+ GPIO_DOCK_INT,
+ GPIO_JIG_ON,
+};
+
+static struct gpio connector_gpios[] = {
+ [GPIO_ACCESSORY_EN] = {
+ .flags = GPIOF_OUT_INIT_LOW,
+ .gpio = 172,
+ .label = "ACCESSORY_EN",
+ },
+ [GPIO_ACCESSORY_INT] = {
+ .flags = GPIOF_IN,
+ .gpio = 39,
+ .label = "ACCESSORY_INT_1.8V",
+ },
+ [GPIO_DOCK_INT] = {
+ .flags = GPIOF_IN,
+ .gpio = 31,
+ .label = "DOCK_INT",
+ },
+ [GPIO_JIG_ON] = {
+ .flags = GPIOF_IN,
+ .gpio = 55,
+ .label = "JIG_ON_18",
+ },
+};
+
+enum {
+ GPIO_USB_SEL1 = 0,
+ GPIO_USB_SEL2,
+ GPIO_UART_SEL
+};
+
+static struct gpio uart_sw_gpios[] = {
+ [GPIO_USB_SEL1] = {
+ .flags = GPIOF_OUT_INIT_HIGH,
+ .gpio = 154,
+ .label = "USB_SEL1",
+ },
+ [GPIO_USB_SEL2] = {
+ .flags = GPIOF_OUT_INIT_HIGH,
+ .gpio = 60,
+ .label = "USB_SEL2",
+ },
+ [GPIO_UART_SEL] = {
+ .flags = GPIOF_OUT_INIT_LOW,
+ .gpio = 47,
+ .label = "UART_SEL",
+ },
+};
+
+/* STMPE811 */
+static struct i2c_board_info __initdata espresso_i2c6_boardinfo[] = {
+ {
+ I2C_BOARD_INFO("stmpe811", 0x82>>1),
+ },
+};
+
+static ssize_t espresso_usb_sel_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf);
+static ssize_t espresso_usb_sel_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size);
+
+static ssize_t espresso_uart_sel_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf);
+static ssize_t espresso_uart_sel_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size);
+
+static ssize_t espresso_usb_state_show(struct device *dev,
+ struct device_attribute *attr, char *buf);
+
+static ssize_t espresso_jig_on_show(struct device *dev,
+ struct device_attribute *attr, char *buf);
+
+static ssize_t espresso_adc_show(struct device *dev,
+ struct device_attribute *attr, char *buf);
+
+static DEVICE_ATTR(usb_sel, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
+ espresso_usb_sel_show, espresso_usb_sel_store);
+static DEVICE_ATTR(uart_sel, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
+ espresso_uart_sel_show, espresso_uart_sel_store);
+static DEVICE_ATTR(usb_state, S_IRUGO, espresso_usb_state_show, NULL);
+static DEVICE_ATTR(jig_on, S_IRUSR | S_IWUSR, espresso_jig_on_show, NULL);
+static DEVICE_ATTR(adc, S_IRUSR | S_IRGRP, espresso_adc_show, NULL);
+
+static struct attribute *manual_switch_sel_attributes[] = {
+ &dev_attr_usb_sel.attr,
+ &dev_attr_uart_sel.attr,
+ &dev_attr_usb_state.attr,
+ &dev_attr_jig_on.attr,
+ &dev_attr_adc.attr,
+ NULL,
+};
+
+static const struct attribute_group manual_switch_sel_group = {
+ .attrs = manual_switch_sel_attributes,
+};
+
+static void espresso_set_dock_switch(int state)
+{
+ struct omap4_otg *espresso_otg = &espresso_otg_xceiv;
+
+ switch_set_state(&espresso_otg->dock_switch, state);
+}
+
+static void espresso_set_audio_switch(int state)
+{
+ struct omap4_otg *espresso_otg = &espresso_otg_xceiv;
+
+ switch_set_state(&espresso_otg->audio_switch, state);
+}
+
+static void omap4_vusb_enable(struct omap4_otg *otg, bool enable)
+{
+ /* delay getting the regulator until later */
+ if (IS_ERR_OR_NULL(otg->vusb)) {
+ otg->vusb = regulator_get(&otg->dev, "vusb");
+ if (IS_ERR(otg->vusb)) {
+ dev_err(&otg->dev, "cannot get vusb regulator\n");
+ return;
+ }
+ }
+
+ if (enable) {
+ regulator_enable(otg->vusb);
+ otg->reg_on = true;
+ } else if (otg->reg_on) {
+ regulator_disable(otg->vusb);
+ otg->reg_on = false;
+ }
+}
+
+static void espresso_accessory_power(u32 device, bool enable)
+{
+ int gpio_acc_en = connector_gpios[GPIO_ACCESSORY_EN].gpio;
+ static u32 acc_device;
+
+ /*
+ token info
+ 0 : power off,
+ 1 : Keyboard dock
+ 2 : USB
+ */
+
+ pr_info("accessory_power: acc_device 0x%x, new %d : %s\n",
+ acc_device, device, enable ? "ON" : "OFF");
+
+ if (enable) {
+ acc_device |= (1 << device);
+ gpio_set_value(gpio_acc_en, 1);
+
+ } else {
+
+ if (device == 0) {
+ pr_info("accessory_power: force turn off\n");
+ gpio_set_value(gpio_acc_en, 0);
+
+ } else {
+ acc_device &= ~(1 << device);
+ if (acc_device == 0) {
+ pr_info("accessory_power: turn off\n");
+ gpio_set_value(gpio_acc_en, 0);
+ } else
+ pr_info("accessory_power: skip\n");
+ }
+ }
+}
+
+static void espresso_set_vbus_drive(bool enable)
+{
+ espresso_accessory_power(2, enable);
+}
+
+static void espresso_ap_usb_attach(struct omap4_otg *otg)
+{
+ omap4_vusb_enable(otg, true);
+
+ otg->otg.default_a = false;
+ otg->otg.state = OTG_STATE_B_IDLE;
+ otg->otg.last_event = USB_EVENT_VBUS_CHARGER;
+
+ atomic_notifier_call_chain(&otg->otg.notifier,
+ USB_EVENT_VBUS_CHARGER,
+ otg->otg.gadget);
+}
+
+static void espresso_ap_usb_detach(struct omap4_otg *otg)
+{
+ omap4_vusb_enable(otg, false);
+
+ otg->otg.default_a = false;
+ otg->otg.state = OTG_STATE_B_IDLE;
+
+ if (otg->otg.last_event != USB_EVENT_VBUS_CHARGER) {
+ otg->otg.last_event = USB_EVENT_NONE;
+ atomic_notifier_call_chain(&otg->otg.notifier,
+ USB_EVENT_NONE,
+ otg->otg.gadget);
+ } else {
+ otg->otg.last_event = USB_EVENT_NONE;
+ pr_info("VBUS OFF before detecting the cable type\n");
+ }
+
+ atomic_notifier_call_chain(&otg->otg.notifier,
+ USB_EVENT_CHARGER_NONE,
+ otg->otg.gadget);
+}
+
+static void espresso_usb_host_attach(struct omap4_otg *otg)
+{
+ pr_info("[%s]\n", __func__);
+ /* Accessory power down needed */
+ espresso_accessory_power(0, 0);
+
+ omap4_vusb_enable(otg, true);
+
+ otg->otg.state = OTG_STATE_A_IDLE;
+ otg->otg.default_a = true;
+ otg->otg.last_event = USB_EVENT_ID;
+
+ atomic_notifier_call_chain(&otg->otg.notifier,
+ USB_EVENT_ID,
+ otg->otg.gadget);
+}
+
+static void espresso_usb_host_detach(struct omap4_otg *otg)
+{
+ otg->otg.state = OTG_STATE_B_IDLE;
+ otg->otg.default_a = false;
+ otg->otg.last_event = USB_EVENT_NONE;
+
+ atomic_notifier_call_chain(&otg->otg.notifier,
+ USB_EVENT_HOST_NONE,
+ otg->otg.gadget);
+
+ espresso_set_vbus_drive(false);
+ omap4_vusb_enable(otg, false);
+}
+
+static void espresso_cp_usb_attach(void)
+{
+ gpio_set_value(uart_sw_gpios[GPIO_USB_SEL1].gpio, 0);
+ gpio_set_value(uart_sw_gpios[GPIO_USB_SEL2].gpio, 0);
+
+ sysfs_notify(&sec_switch_dev->kobj, NULL, "usb_sel");
+}
+
+static void espresso_cp_usb_detach(void)
+{
+ gpio_set_value(uart_sw_gpios[GPIO_USB_SEL1].gpio, 1);
+ gpio_set_value(uart_sw_gpios[GPIO_USB_SEL2].gpio, 0);
+
+ sysfs_notify(&sec_switch_dev->kobj, NULL, "usb_sel");
+}
+
+static void espresso_ap_uart_actions(void)
+{
+ gpio_set_value(uart_sw_gpios[GPIO_UART_SEL].gpio, IF_UART_SEL_AP);
+}
+
+static void espresso_cp_uart_actions(void)
+{
+ gpio_set_value(uart_sw_gpios[GPIO_UART_SEL].gpio, IF_UART_SEL_CP);
+}
+
+static void espresso_gpio_set_for_adc_check_1(void)
+{
+ gpio_set_value(uart_sw_gpios[GPIO_USB_SEL1].gpio, 0);
+ gpio_set_value(uart_sw_gpios[GPIO_USB_SEL2].gpio, 1);
+}
+
+static void espresso_gpio_rel_for_adc_check_1(void)
+{
+ struct omap4_otg *espresso_otg = &espresso_otg_xceiv;
+
+ if (espresso_otg->usb_manual_mode == ESPRESSO_MANUAL_USB_MODEM)
+ espresso_cp_usb_attach();
+ else
+ espresso_cp_usb_detach();
+}
+
+int omap4_espresso_get_adc(enum espresso_adc_ch ch)
+{
+ int adc;
+ int i;
+ int adc_tmp;
+ int adc_min = MAX_ADC_VAL;
+ int adc_max = MIN_ADC_VAL;
+ int adc_sum = 0;
+ u8 stmpe811_ch = ADC_CHANNEL_IN2;
+
+ if (ch == REMOTE_SENSE)
+ stmpe811_ch = ADC_CHANNEL_IN1;
+ else if (ch == ADC_CHECK_1)
+ stmpe811_ch = ADC_CHANNEL_IN2;
+ else if (ch == ACCESSORY_ID)
+ stmpe811_ch = ADC_CHANNEL_IN3;
+ else if (ch == EAR_ADC_35)
+ stmpe811_ch = ADC_CHANNEL_IN0;
+
+ if (ch == ADC_CHECK_1) {
+ /* HQRL Standard defines that time margin from Vbus5V detection
+ * to ADC_CHECK_1 voltage up should be more than 400ms.
+ */
+ msleep(400); /* delay for unstable cable connection */
+
+ espresso_gpio_set_for_adc_check_1();
+
+ msleep(150); /* delay for slow increase of line voltage */
+
+ for (i = 0; i < 5; i++) {
+ usleep_range(5000, 5500);
+ adc_tmp = stmpe811_adc_get_value(stmpe811_ch);
+ pr_info("adc_check_1 adc=%d\n", adc_tmp);
+ adc_sum += adc_tmp;
+ if (adc_max < adc_tmp)
+ adc_max = adc_tmp;
+
+ if (adc_min > adc_tmp)
+ adc_min = adc_tmp;
+ }
+ espresso_gpio_rel_for_adc_check_1();
+ adc = (adc_sum - adc_max - adc_min) / 3;
+ } else
+ adc = stmpe811_adc_get_value(stmpe811_ch);
+
+ return adc;
+}
+
+static void espresso_con_usb_charger_attached(struct omap4_otg *otg)
+{
+ int val;
+
+ /* USB cable connected */
+ pr_info("%s, USB_EVENT_VBUS\n", __func__);
+
+ val = gpio_get_value(GPIO_TA_NCONNECTED);
+ if (val < 0) {
+ pr_err("usb ta_nconnected: gpio_get_value error %d\n", val);
+ return;
+ }
+
+ if (!val) { /* connected */
+ otg->otg.default_a = false;
+ otg->otg.state = OTG_STATE_B_IDLE;
+ otg->otg.last_event = USB_EVENT_VBUS;
+
+ atomic_notifier_call_chain(&otg->otg.notifier,
+ USB_EVENT_VBUS, otg->otg.gadget);
+ } else { /* disconnected */
+ pr_info("%s, VBUS OFF : USB_EVENT_VBUS is not sent\n",
+ __func__);
+ }
+}
+
+static void espresso_con_ta_charger_attached(struct omap4_otg *otg)
+{
+ int val;
+
+ /* Change to USB_EVENT_CHARGER for sleep */
+ pr_info("%s, USB_EVENT_CHARGER\n", __func__);
+
+ val = gpio_get_value(GPIO_TA_NCONNECTED);
+ if (val < 0) {
+ pr_err("usb ta_nconnected: gpio_get_value error %d\n", val);
+ return;
+ }
+
+ if (!val) { /* connected */
+ otg->otg.default_a = false;
+ otg->otg.state = OTG_STATE_B_IDLE;
+ otg->otg.last_event = USB_EVENT_CHARGER;
+
+ atomic_notifier_call_chain(&otg->otg.notifier,
+ USB_EVENT_CHARGER,
+ otg->otg.gadget);
+ } else { /* disconnected */
+ pr_info("%s, VBUS OFF : USB_EVENT_CHARGER is not sent\n",
+ __func__);
+ }
+}
+
+static void espresso_con_charger_detached(void)
+{
+}
+
+static void espresso_deskdock_attached(void)
+{
+ espresso_set_dock_switch(UEVENT_DOCK_DESK);
+}
+
+static void espresso_deskdock_detached(void)
+{
+ espresso_set_dock_switch(UEVENT_DOCK_NONE);
+}
+
+static void espresso_30pin_detected(int device, bool connected)
+{
+ struct omap4_otg *espresso_otg = &espresso_otg_xceiv;
+
+ if (connected)
+ espresso_otg->current_device |= BIT(device);
+ else
+ espresso_otg->current_device &= ~(BIT(device));
+
+ pr_info("cable detect:%s %s, current device = 0x%04x\n",
+ device_names[device], (connected) ? "attach" : "detach",
+ espresso_otg->current_device);
+
+ switch (device) {
+ case P30_OTG:
+ if (connected)
+ espresso_usb_host_attach(espresso_otg);
+ else
+ espresso_usb_host_detach(espresso_otg);
+ break;
+ case P30_KEYBOARDDOCK:
+ if (connected) {
+ espresso_set_dock_switch(UEVENT_DOCK_KEYBOARD);
+#ifdef CONFIG_SND_OMAP_SOC_ESPRESSO
+ notify_dock_status(1);
+#endif
+ } else {
+ espresso_set_dock_switch(UEVENT_DOCK_NONE);
+#ifdef CONFIG_SND_OMAP_SOC_ESPRESSO
+ notify_dock_status(0);
+#endif
+ }
+ break;
+ case P30_DESKDOCK:
+ if (connected) {
+ espresso_deskdock_attached();
+#ifdef CONFIG_SND_OMAP_SOC_ESPRESSO
+ notify_dock_status(1);
+#endif
+ } else {
+ espresso_deskdock_detached();
+#ifdef CONFIG_SND_OMAP_SOC_ESPRESSO
+ notify_dock_status(0);
+#endif
+ }
+ break;
+ case P30_CARDOCK:
+ if (connected) {
+ espresso_set_dock_switch(UEVENT_DOCK_CAR);
+#ifdef CONFIG_SND_OMAP_SOC_ESPRESSO
+ notify_dock_status(1);
+#endif
+ } else {
+ espresso_set_dock_switch(UEVENT_DOCK_NONE);
+#ifdef CONFIG_SND_OMAP_SOC_ESPRESSO
+ notify_dock_status(0);
+#endif
+ }
+ break;
+ case P30_JIG:
+ if (connected) {
+ check_jig_status(1);
+ if (espresso_otg->uart_manual_mode ==
+ ESPRESSO_MANUAL_UART_MODEM)
+ espresso_cp_uart_actions();
+ else
+ espresso_ap_uart_actions();
+ } else
+ check_jig_status(0);
+ break;
+ case P30_USB:
+ if (connected)
+ espresso_con_usb_charger_attached(espresso_otg);
+ else
+ espresso_con_charger_detached();
+ break;
+ case P30_TA:
+ if (connected)
+ espresso_con_ta_charger_attached(espresso_otg);
+ else
+ espresso_con_charger_detached();
+ break;
+ case P30_EARJACK_WITH_DOCK:
+ if (connected)
+ espresso_set_audio_switch(UEVENT_EARJACK_ATTACHED);
+ else
+ espresso_set_audio_switch(UEVENT_EARJACK_DETACHED);
+ break;
+ case P30_ANAL_TV_OUT:
+ pr_warning("This accessory is not supported.\n");
+ break;
+ default:
+ pr_warning("wrong cable detection information!(%d)\n", device);
+ break;
+ }
+}
+
+void omap4_espresso_usb_detected(int cable_type)
+{
+ struct omap4_otg *espresso_otg = &espresso_otg_xceiv;
+
+ switch (cable_type) {
+ case CABLE_TYPE_USB:
+ espresso_30pin_detected(P30_USB, 1);
+ break;
+ case CABLE_TYPE_AC:
+ espresso_30pin_detected(P30_TA, 1);
+ break;
+ case CABLE_TYPE_NONE:
+ if (espresso_otg->current_device & BIT(P30_USB))
+ espresso_30pin_detected(P30_USB, 0);
+ else
+ espresso_30pin_detected(P30_TA, 0);
+ break;
+ default:
+ pr_warning("wrong usb detected information!\n");
+ break;
+
+ }
+}
+
+static s16 espresso_get_accessory_adc(void)
+{
+ return omap4_espresso_get_adc(ACCESSORY_ID);
+}
+
+/* 30pin connector */
+struct acc_con_platform_data espresso_con_pdata = {
+ .detected = espresso_30pin_detected,
+ .get_accessory_adc = espresso_get_accessory_adc,
+};
+
+struct platform_device espresso_device_connector = {
+ .name = "acc_con",
+ .id = -1,
+ .dev = {
+ .platform_data = &espresso_con_pdata,
+ },
+};
+
+/* uart_switch, usb_sel */
+static ssize_t espresso_uart_sel_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct omap4_otg *espresso_otg = &espresso_otg_xceiv;
+ const char *mode;
+
+ switch (espresso_otg->uart_manual_mode) {
+ case ESPRESSO_MANUAL_UART_AP:
+ mode = "AP";
+ break;
+ case ESPRESSO_MANUAL_UART_MODEM:
+ mode = "CP";
+ break;
+ default:
+ mode = "NONE";
+ };
+
+ return sprintf(buf, "%s\n", mode);
+}
+
+static ssize_t espresso_uart_sel_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct omap4_otg *espresso_otg = &espresso_otg_xceiv;
+
+ mutex_lock(&espresso_otg->lock);
+
+ if (!strncasecmp(buf, "AP", 2)) {
+ espresso_otg->uart_manual_mode = ESPRESSO_MANUAL_UART_AP;
+
+ if (espresso_otg->current_device & BIT(P30_JIG))
+ espresso_ap_uart_actions();
+ } else if (!strncasecmp(buf, "CP", 2)) {
+ espresso_otg->uart_manual_mode = ESPRESSO_MANUAL_UART_MODEM;
+
+ if (espresso_otg->current_device & BIT(P30_JIG))
+ espresso_cp_uart_actions();
+ } else if (!strncasecmp(buf, "NONE", 4)) {
+ espresso_otg->uart_manual_mode = ESPRESSO_MANUAL_UART_NONE;
+
+ if (espresso_otg->current_device & BIT(P30_JIG))
+ espresso_ap_uart_actions();
+ }
+
+ mutex_unlock(&espresso_otg->lock);
+
+ return size;
+}
+
+static ssize_t espresso_usb_sel_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct omap4_otg *espresso_otg = &espresso_otg_xceiv;
+ const char *mode;
+
+ switch (espresso_otg->usb_manual_mode) {
+ case ESPRESSO_MANUAL_USB_AP:
+ mode = "PDA";
+ break;
+ case ESPRESSO_MANUAL_USB_MODEM:
+ mode = "MODEM";
+ break;
+ default:
+ mode = "NONE";
+ };
+
+ return sprintf(buf, "%s\n", mode);
+}
+
+static ssize_t espresso_usb_sel_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct omap4_otg *espresso_otg = &espresso_otg_xceiv;
+ int old_mode;
+
+ mutex_lock(&espresso_otg->lock);
+
+ old_mode = espresso_otg->usb_manual_mode;
+
+ if (!strncasecmp(buf, "PDA", 3)) {
+ espresso_otg->usb_manual_mode = ESPRESSO_MANUAL_USB_AP;
+
+ /* If we are transitioning from CP USB to AP USB then notify the
+ * USB stack that is now attached.
+ */
+ if ((espresso_otg->current_device & BIT(P30_USB)) &&
+ (old_mode != ESPRESSO_MANUAL_USB_AP)) {
+ espresso_cp_usb_detach();
+ espresso_ap_usb_attach(espresso_otg);
+ }
+ } else if (!strncasecmp(buf, "MODEM", 5)) {
+ espresso_otg->usb_manual_mode = ESPRESSO_MANUAL_USB_MODEM;
+
+ /* If we are transitioning from AP USB to CP USB then notify the
+ * USB stack that is has been detached.
+ */
+ if ((espresso_otg->current_device & BIT(P30_USB)) &&
+ (old_mode != ESPRESSO_MANUAL_USB_MODEM)) {
+ espresso_ap_usb_detach(espresso_otg);
+ espresso_cp_usb_attach();
+ }
+ } else if (!strncasecmp(buf, "NONE", 5)) {
+ espresso_otg->usb_manual_mode = ESPRESSO_MANUAL_USB_NONE;
+
+ /* If we are transitioning from CP USB to AP USB then notify the
+ * USB stack that it is now attached.
+ */
+ if ((espresso_otg->current_device & BIT(P30_USB)) &&
+ (old_mode != ESPRESSO_MANUAL_USB_MODEM)) {
+ espresso_cp_usb_detach();
+ espresso_ap_usb_attach(espresso_otg);
+ }
+ }
+
+ mutex_unlock(&espresso_otg->lock);
+
+ return size;
+}
+
+static ssize_t espresso_usb_state_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct omap4_otg *espresso_otg = &espresso_otg_xceiv;
+ const char *mode;
+
+ if (espresso_otg->current_device & BIT(P30_USB))
+ mode = "USB_STATE_CONFIGURED";
+ else
+ mode = "USB_STATE_NOT_CONFIGURED";
+
+ return sprintf(buf, "%s\n", mode);
+}
+
+static ssize_t espresso_jig_on_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct omap4_otg *espresso_otg = &espresso_otg_xceiv;
+ const char *mode;
+
+ if (espresso_otg->current_device & BIT(P30_JIG))
+ mode = "1";
+ else
+ mode = "0";
+
+ return sprintf(buf, "%s\n", mode);
+}
+
+/* Factory test application reads /sys/class/sec/switch/adc.
+ If key_string_on value is 0x1C, the application enables key-strings.
+ If key_string_on value is 0, the application disables key-strings.
+ This is Samsung standard.
+ */
+static ssize_t espresso_adc_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ s16 adc_val;
+ u8 key_string_on;
+
+ adc_val = espresso_get_accessory_adc();
+ pr_info("accessory_id adc value = %d\n", adc_val);
+
+ if ((3600 < adc_val) && (adc_val < 3800))
+ key_string_on = 0x1C;
+ else
+ key_string_on = 0;
+
+ return sprintf(buf, "%x\n", key_string_on);
+}
+
+static int espresso_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 espresso_otg_set_peripheral(struct otg_transceiver *otg,
+ struct usb_gadget *gadget)
+{
+ otg->gadget = gadget;
+ if (!gadget)
+ otg->state = OTG_STATE_UNDEFINED;
+ return 0;
+}
+
+static void espresso_otg_work(struct work_struct *data)
+{
+ struct omap4_otg *espresso_otg =
+ container_of(data, struct omap4_otg, set_vbus_work);
+
+ pr_info("otg %s(%d): current device %04x\n",
+ __func__, __LINE__,
+ espresso_otg->current_device);
+
+ mutex_lock(&espresso_otg->lock);
+
+ /* Only allow VBUS drive when in host mode. */
+ if (!(espresso_otg->current_device & BIT(P30_OTG))) {
+ pr_info("otg current device is not USB Host.\n");
+ mutex_unlock(&espresso_otg->lock);
+ return;
+ }
+
+ espresso_set_vbus_drive(espresso_otg->need_vbus_drive);
+
+ mutex_unlock(&espresso_otg->lock);
+}
+
+static int espresso_otg_set_vbus(struct otg_transceiver *otg, bool enabled)
+{
+ struct omap4_otg *espresso_otg =
+ container_of(otg, struct omap4_otg, otg);
+ dev_dbg(otg->dev, "vbus %s\n", enabled ? "on" : "off");
+
+ espresso_otg->need_vbus_drive = enabled;
+ schedule_work(&espresso_otg->set_vbus_work);
+
+ return 0;
+}
+
+static int espresso_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 espresso_otg_phy_shutdown(struct otg_transceiver *otg)
+{
+ omap4430_phy_power(otg->dev, 0, 0);
+}
+
+static int espresso_otg_set_suspend(struct otg_transceiver *otg, int suspend)
+{
+ return omap4430_phy_suspend(otg->dev, suspend);
+}
+
+static irqreturn_t ta_nconnected_irq(int irq, void *_otg)
+{
+ struct omap4_otg *otg = _otg;
+ int val;
+
+ val = gpio_get_value(GPIO_TA_NCONNECTED);
+ if (val < 0) {
+ pr_err("usb ta_nconnected: gpio_get_value error %d\n", val);
+ return IRQ_HANDLED;
+ }
+
+ pr_info("usb ta_nconnected_irq : VBUS %s\n", val ? "OFF" : "ON");
+
+ irq_set_irq_type(irq, val ?
+ IRQF_TRIGGER_LOW : IRQF_TRIGGER_HIGH);
+
+ if (!val) /* connected */
+ espresso_ap_usb_attach(otg);
+ else /* disconnected */
+ espresso_ap_usb_detach(otg);
+
+ return IRQ_HANDLED;
+}
+
+static int espresso_vbus_detect_init(struct omap4_otg *otg)
+{
+ int status = 0;
+ int irq = 0;
+ int val;
+
+ status = gpio_request(GPIO_TA_NCONNECTED, "TA_nCONNECTED");
+ if (status < 0) {
+ dev_err(&otg->dev, "gpio %d request failed.\n", GPIO_TA_NCONNECTED);
+ return status;
+ }
+
+ status = gpio_direction_input(GPIO_TA_NCONNECTED);
+ if (status < 0) {
+ dev_err(&otg->dev, "failed to set gpio %d as input\n",
+ GPIO_TA_NCONNECTED);
+ return status;
+ }
+
+ irq = gpio_to_irq(GPIO_TA_NCONNECTED);
+ val = gpio_get_value(GPIO_TA_NCONNECTED);
+
+ status = request_threaded_irq(irq, NULL, ta_nconnected_irq,
+ (val ? IRQF_TRIGGER_LOW : IRQF_TRIGGER_HIGH) | \
+ IRQF_ONESHOT | IRQF_NO_SUSPEND,
+ "TA_nConnected", otg);
+ if (status < 0) {
+ dev_err(&otg->dev, "request irq %d failed for gpio %d\n",
+ irq, GPIO_TA_NCONNECTED);
+ return status;
+ }
+
+ return 0;
+}
+
+/* dock keyboard */
+static struct dock_keyboard_callback {
+ struct input_dev *dev;
+ int (*cb) (struct input_dev *dev, bool connected);
+} espresso_dock_keyboard_cb;
+
+static int espresso_dock_keyboard_callback(bool connected)
+{
+ if (espresso_dock_keyboard_cb.dev && espresso_dock_keyboard_cb.cb)
+ return espresso_dock_keyboard_cb.cb(espresso_dock_keyboard_cb.
+ dev, connected);
+ return 0;
+}
+
+static void espresso_dock_keyboard_power(bool on)
+{
+ struct omap4_otg *espresso_otg = &espresso_otg_xceiv;
+
+ if (on) {
+ if (espresso_otg->uart_manual_mode ==
+ ESPRESSO_MANUAL_UART_MODEM) {
+ pr_info("kbd: switch UART IF to AP\n");
+ espresso_ap_uart_actions();
+ }
+ espresso_accessory_power(1, 1);
+ } else {
+ espresso_accessory_power(1, 0);
+ if (espresso_otg->uart_manual_mode ==
+ ESPRESSO_MANUAL_UART_MODEM) {
+ pr_info("kbd: switch UART IF to CP\n");
+ espresso_cp_uart_actions();
+ }
+ }
+}
+
+static void espresso_dock_keyboard_register_cb(struct input_dev *dev, void *cb)
+{
+ espresso_dock_keyboard_cb.dev = dev;
+ espresso_dock_keyboard_cb.cb = cb;
+}
+
+struct dock_keyboard_platform_data espresso_dock_keyboard_pdata = {
+ .power = espresso_dock_keyboard_power,
+ .register_cb = espresso_dock_keyboard_register_cb,
+};
+
+struct platform_device espresso_device_dock_keyboard = {
+ .name = KBD_DRV_NAME,
+ .id = 0,
+ .dev = {
+ .platform_data = &espresso_dock_keyboard_pdata,
+ },
+};
+
+static void __init espresso_switch_initial_setup(void)
+{
+ struct omap4_otg *espresso_otg = &espresso_otg_xceiv;
+
+ if (init_switch_sel & MASK_SWITCH_UART_AP) {
+ espresso_ap_uart_actions();
+ espresso_otg->uart_manual_mode = ESPRESSO_MANUAL_UART_AP;
+ } else {
+ espresso_cp_uart_actions();
+ espresso_otg->uart_manual_mode = ESPRESSO_MANUAL_UART_MODEM;
+ }
+
+ if (init_switch_sel & MASK_SWITCH_USB_AP) {
+ espresso_cp_usb_detach();
+ espresso_otg->usb_manual_mode = ESPRESSO_MANUAL_USB_AP;
+ } else {
+ espresso_cp_usb_attach();
+ espresso_otg->usb_manual_mode = ESPRESSO_MANUAL_USB_MODEM;
+ }
+
+}
+
+static int __init espresso_save_init_switch_param(char *str)
+{
+ int ret;
+
+ ret = kstrtoint(str, 10, &init_switch_sel);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+__setup("switch_sel=", espresso_save_init_switch_param);
+
+static void connector_gpio_init(void)
+{
+ if ((board_is_espresso10() && system_rev >= 8) ||
+ (!board_is_espresso10() && system_rev >= 10)) {
+ connector_gpios[GPIO_ACCESSORY_INT].gpio = 2;
+ }
+
+ gpio_request_array(connector_gpios, ARRAY_SIZE(connector_gpios));
+ gpio_request_array(uart_sw_gpios, ARRAY_SIZE(uart_sw_gpios));
+}
+
+static int __init espresso_plugged_usb_cable_init(void)
+{
+ struct omap4_otg *espresso_otg = &espresso_otg_xceiv;
+
+ /* USB connected */
+ if (gpio_get_value(GPIO_TA_NCONNECTED) == 0)
+ omap4_vusb_enable(espresso_otg, true);
+
+ return 0;
+}
+fs_initcall(espresso_plugged_usb_cable_init);
+
+void __init omap4_espresso_connector_init(void)
+{
+ struct omap4_otg *espresso_otg = &espresso_otg_xceiv;
+ int ret;
+
+ connector_gpio_init();
+ mutex_init(&espresso_otg->lock);
+ INIT_WORK(&espresso_otg->set_vbus_work, espresso_otg_work);
+ device_initialize(&espresso_otg->dev);
+ dev_set_name(&espresso_otg->dev, "%s", "espresso_otg");
+ ret = device_add(&espresso_otg->dev);
+ if (ret) {
+ pr_err("%s: cannot reg device '%s' (%d)\n", __func__,
+ dev_name(&espresso_otg->dev), ret);
+ return;
+ }
+
+ dev_set_drvdata(&espresso_otg->dev, espresso_otg);
+
+ espresso_otg->otg.dev = &espresso_otg->dev;
+ espresso_otg->otg.label = "espresso_otg_xceiv";
+ espresso_otg->otg.set_host = espresso_otg_set_host;
+ espresso_otg->otg.set_peripheral = espresso_otg_set_peripheral;
+ espresso_otg->otg.set_suspend = espresso_otg_set_suspend;
+ espresso_otg->otg.set_vbus = espresso_otg_set_vbus;
+ espresso_otg->otg.init = espresso_otg_phy_init;
+ espresso_otg->otg.shutdown = espresso_otg_phy_shutdown;
+
+ ATOMIC_INIT_NOTIFIER_HEAD(&espresso_otg->otg.notifier);
+
+ ret = otg_set_transceiver(&espresso_otg->otg);
+ if (ret)
+ pr_err("espresso_otg: cannot set transceiver (%d)\n", ret);
+
+ omap4430_phy_init(&espresso_otg->dev);
+
+ espresso_otg_set_suspend(&espresso_otg->otg, 0);
+ espresso_vbus_detect_init(espresso_otg);
+
+ sec_switch_dev = device_create(sec_class, NULL, 0, NULL, "switch");
+ if (IS_ERR(sec_switch_dev)) {
+ pr_err("(%s): failed to created device (switch_dev)!\n",
+ __func__);
+ goto switch_dev_fail;
+ }
+
+ ret = sysfs_create_group(&sec_switch_dev->kobj,
+ &manual_switch_sel_group);
+ if (ret < 0)
+ pr_err("fail to create manual switch_sel sysfs group (%d)\n",
+ ret);
+switch_dev_fail:
+ espresso_switch_initial_setup();
+
+ /* dock keyboard */
+ espresso_dock_keyboard_pdata.dock_irq_gpio =
+ connector_gpios[GPIO_ACCESSORY_INT].gpio;
+
+ platform_device_register(&espresso_device_dock_keyboard);
+
+ /* ADC IC (STMPE811) */
+ i2c_register_board_info(6, espresso_i2c6_boardinfo,
+ ARRAY_SIZE(espresso_i2c6_boardinfo));
+
+ /* 30pin connector */
+ espresso_con_pdata.accessory_irq_gpio =
+ connector_gpios[GPIO_ACCESSORY_INT].gpio;
+ espresso_con_pdata.dock_irq_gpio = connector_gpios[GPIO_DOCK_INT].gpio;
+ espresso_con_pdata.jig_on_gpio = connector_gpios[GPIO_JIG_ON].gpio;
+ espresso_con_pdata.dock_keyboard_cb = espresso_dock_keyboard_callback;
+
+ platform_device_register(&espresso_device_connector);
+
+ espresso_otg->dock_switch.name = "dock";
+ switch_dev_register(&espresso_otg->dock_switch);
+
+ espresso_otg->audio_switch.name = "usb_audio";
+ switch_dev_register(&espresso_otg->audio_switch);
+
+ espresso_otg->current_device = 0;
+}
diff --git a/arch/arm/mach-omap2/board-espresso-display.c b/arch/arm/mach-omap2/board-espresso-display.c
new file mode 100644
index 0000000..60aa7a9
--- /dev/null
+++ b/arch/arm/mach-omap2/board-espresso-display.c
@@ -0,0 +1,195 @@
+/* arch/arm/mach-omap2/board-espresso-display.c
+ *
+ * Copyright (C) 2011 Samsung Electronics Co, Ltd.
+ *
+ * Based on mach-omap2/board-tuna-display.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/err.h>
+#include <linux/gpio.h>
+#include <linux/kernel.h>
+#include <linux/omapfb.h>
+#include <linux/regulator/consumer.h>
+#include <linux/platform_data/panel-ltn.h>
+
+#include <plat/omap_hwmod.h>
+#include <plat/android-display.h>
+
+#include <video/omapdss.h>
+
+#include "board-espresso.h"
+
+#ifdef CONFIG_FB_OMAP_BOOTLOADER_INIT
+#include <plat/clock.h>
+#include <linux/clk.h>
+#endif
+
+#define GPIO_LED_BACKLIGHT_RESET 95
+#define GPIO_LCD_EN 135
+#define GPIO_LVDS_NSHDN 136
+
+static void espresso_lcd_set_power(bool enable)
+{
+ pr_debug("%s: %d\n", __func__, enable);
+ gpio_set_value(GPIO_LCD_EN, enable);
+}
+
+static void espresso_lcd_set_gptimer_idle(void)
+{
+ struct omap_hwmod *timer10_hwmod;
+ pr_debug("espresso_lcd_set_gptimer_idle\n");
+
+ timer10_hwmod = omap_hwmod_lookup("timer10");
+ if (likely(timer10_hwmod))
+ omap_hwmod_idle(timer10_hwmod);
+}
+
+static struct ltn_panel_data espresso_panel_data = {
+ .set_power = espresso_lcd_set_power,
+ .set_gptimer_idle = espresso_lcd_set_gptimer_idle,
+ .lvds_nshdn_gpio = GPIO_LVDS_NSHDN,
+ .led_backlight_reset_gpio = GPIO_LED_BACKLIGHT_RESET,
+ .backlight_gptimer_num = 10,
+ .brightness_table = {
+ .platform_value = {BRIGHTNESS_OFF, BRIGHTNESS_DIM, BRIGHTNESS_MIN,
+ BRIGHTNESS_25, BRIGHTNESS_DEFAULT, BRIGHTNESS_MAX},
+ .kernel_value = { 0, 2, 3, 8, 40, 85 },
+ },
+};
+
+static struct omap_dss_device espresso_lcd_device = {
+ .name = "lcd",
+ .driver_name = "ltn_panel",
+ .type = OMAP_DISPLAY_TYPE_DPI,
+ .phy.dpi.data_lines = 24,
+ .data = &espresso_panel_data,
+ .channel = OMAP_DSS_CHANNEL_LCD2,
+#ifdef CONFIG_FB_OMAP_BOOTLOADER_INIT
+ .skip_init = true,
+#else
+ .skip_init = false,
+#endif
+ .panel = {
+ .timings = {
+ .x_res = 1024,
+ .y_res = 600,
+ .pixel_clock = 56888, /* closest to 56000 */
+ .hfp = 186,
+ .hsw = 50,
+ .hbp = 210,
+ .vfp = 24,
+ .vsw = 10,
+ .vbp = 11,
+ },
+ .width_in_um = 153600,
+ .height_in_um = 90000,
+ },
+};
+
+static struct omap_dss_device espresso10_lcd_config = {
+ .panel = {
+ .timings = {
+ .x_res = 1280,
+ .y_res = 800,
+ .pixel_clock = 69818, /* closest to 69000 */
+ .hfp = 16,
+ .hsw = 48,
+ .hbp = 64,
+ .vfp = 16,
+ .vsw = 3,
+ .vbp = 11,
+ },
+ .width_in_um = 216960,
+ .height_in_um = 135600,
+ },
+};
+
+static struct omap_dss_device *espresso_dss_devices[] = {
+ &espresso_lcd_device,
+};
+
+static struct omap_dss_board_info espresso_dss_data = {
+ .num_devices = ARRAY_SIZE(espresso_dss_devices),
+ .devices = espresso_dss_devices,
+ .default_device = &espresso_lcd_device,
+};
+
+static struct omapfb_platform_data espresso_fb_pdata = {
+ .mem_desc = {
+ .region_cnt = 1,
+ },
+};
+
+void __init omap4_espresso_memory_display_init(void)
+{
+ if (board_is_espresso10())
+ espresso_dss_data.devices[0]->panel = espresso10_lcd_config.panel;
+
+ omap_android_display_setup(&espresso_dss_data,
+ NULL,
+ NULL,
+ &espresso_fb_pdata,
+ get_omap_ion_platform_data());
+}
+
+void __init omap4_espresso_display_early_init(void)
+{
+ struct omap_hwmod *timer10_hwmod;
+ struct omap_hwmod *gpio3_hwmod;
+ struct omap_hwmod *gpio5_hwmod;
+
+ /* correct timer10 hwmod flag settings for espresso board. */
+ timer10_hwmod = omap_hwmod_lookup("timer10");
+ if (likely(timer10_hwmod))
+ timer10_hwmod->flags =
+ (HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET);
+
+ /* correct gpio3 hwmod flag settings for espresso board. */
+ gpio3_hwmod = omap_hwmod_lookup("gpio3");
+ if (likely(gpio3_hwmod))
+ gpio3_hwmod->flags = HWMOD_INIT_NO_RESET;
+
+ /* correct gpio5 hwmod flag settings for espresso board. */
+ gpio5_hwmod = omap_hwmod_lookup("gpio5");
+ if (likely(gpio5_hwmod))
+ gpio5_hwmod->flags = HWMOD_INIT_NO_RESET;
+}
+
+void __init omap4_espresso_display_init(void)
+{
+ int ret;
+#ifdef CONFIG_FB_OMAP_BOOTLOADER_INIT
+ struct clk *dss_dss_fclk;
+#endif
+
+ if (board_is_espresso10())
+ espresso_panel_data.pwm_duty_max = 1600; /* 25kHz */
+ else
+ espresso_panel_data.pwm_duty_max = 1200; /* 32kHz */
+
+#ifdef CONFIG_FB_OMAP_BOOTLOADER_INIT
+ dss_dss_fclk = omap_clk_get_by_name("dss_dss_clk");
+ if (IS_ERR(dss_dss_fclk)) {
+ pr_err("Could not get dss functional clock\n");
+ /* return -ENOENT; */
+ }
+ clk_enable(dss_dss_fclk);
+#endif
+
+ ret = gpio_request(GPIO_LCD_EN, "lcd_en");
+ if (ret < 0)
+ pr_err("%s: gpio_request %d failed!\n", __func__, GPIO_LCD_EN);
+
+ gpio_direction_output(GPIO_LCD_EN, 1);
+
+ omap_display_init(&espresso_dss_data);
+}
diff --git a/arch/arm/mach-omap2/board-espresso-emif.c b/arch/arm/mach-omap2/board-espresso-emif.c
new file mode 100644
index 0000000..c379dd8
--- /dev/null
+++ b/arch/arm/mach-omap2/board-espresso-emif.c
@@ -0,0 +1,48 @@
+/*
+ * 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 <mach/lpddr2-jedec.h>
+#include "board-espresso.h"
+
+struct lpddr2_device_info lpddr2_samsung_4G_S4_dev = {
+ .device_timings = {
+ &lpddr2_jedec_timings_200_mhz,
+ &lpddr2_jedec_timings_400_mhz
+ },
+ .min_tck = &lpddr2_jedec_min_tck,
+ .type = LPDDR2_TYPE_S4,
+ .density = LPDDR2_DENSITY_4Gb,
+ .io_width = LPDDR2_IO_WIDTH_32,
+ .emif_ddr_selfrefresh_cycles = 262144,
+};
+
+/*
+ * 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_espresso_emif_init(void)
+{
+ omap_emif_setup_device_details(&emif_devices, &emif_devices);
+}
diff --git a/arch/arm/mach-omap2/board-espresso-input.c b/arch/arm/mach-omap2/board-espresso-input.c
new file mode 100644
index 0000000..dd1126c
--- /dev/null
+++ b/arch/arm/mach-omap2/board-espresso-input.c
@@ -0,0 +1,295 @@
+/*
+ * Copyright (C) 2012 Samsung Electronics, 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/errno.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/battery.h>
+#include <linux/delay.h>
+#include <linux/platform_data/sec_ts.h>
+#include <linux/touchscreen/synaptics.h>
+#include <asm/mach-types.h>
+#include <plat/omap4-keypad.h>
+
+#include "board-espresso.h"
+#include "mux.h"
+#include "control.h"
+
+#define GPIO_EXT_WAKEUP 3
+
+/* Reversed on p51xx */
+#define GPIO_VOL_UP 30
+#define GPIO_VOL_DN 8
+
+#define GPIO_TSP_INT 46
+#define GPIO_TSP_LDO_ON 54
+#define GPIO_TSP_I2C_SCL 130
+#define GPIO_TSP_I2C_SDA 131
+
+#define GPIO_TSP_VENDOR1 71
+#define GPIO_TSP_VENDOR2 72
+#define GPIO_TSP_VENDOR3 92
+
+static struct gpio_event_direct_entry espresso_gpio_keypad_keys_map_high[] = {
+ {
+ .code = KEY_POWER,
+ .gpio = GPIO_EXT_WAKEUP,
+ },
+};
+
+static struct gpio_event_input_info espresso_gpio_keypad_keys_info_high = {
+ .info.func = gpio_event_input_func,
+ .info.no_suspend = true,
+ .type = EV_KEY,
+ .keymap = espresso_gpio_keypad_keys_map_high,
+ .keymap_size = ARRAY_SIZE(espresso_gpio_keypad_keys_map_high),
+ .flags = GPIOEDF_ACTIVE_HIGH,
+ .debounce_time.tv64 = 2 * NSEC_PER_MSEC,
+};
+
+static struct gpio_event_direct_entry espresso_gpio_keypad_keys_map_low[] = {
+ {
+ .code = KEY_VOLUMEDOWN,
+ .gpio = GPIO_VOL_DN,
+ },
+ {
+ .code = KEY_VOLUMEUP,
+ .gpio = GPIO_VOL_UP,
+ },
+};
+
+static struct gpio_event_input_info espresso_gpio_keypad_keys_info_low = {
+ .info.func = gpio_event_input_func,
+ .info.no_suspend = true,
+ .type = EV_KEY,
+ .keymap = espresso_gpio_keypad_keys_map_low,
+ .keymap_size = ARRAY_SIZE(espresso_gpio_keypad_keys_map_low),
+ .debounce_time.tv64 = 2 * NSEC_PER_MSEC,
+};
+
+static struct gpio_event_info *espresso_gpio_keypad_info[] = {
+ &espresso_gpio_keypad_keys_info_high.info,
+ &espresso_gpio_keypad_keys_info_low.info,
+};
+
+static struct gpio_event_platform_data espresso_gpio_keypad_data = {
+ .name = "espresso-gpio-keypad",
+ .info = espresso_gpio_keypad_info,
+ .info_count = ARRAY_SIZE(espresso_gpio_keypad_info)
+};
+
+static struct platform_device espresso_gpio_keypad_device = {
+ .name = GPIO_EVENT_DEV_NAME,
+ .id = 0,
+ .dev = {
+ .platform_data = &espresso_gpio_keypad_data,
+ },
+};
+
+static void tsp_set_power(bool on)
+{
+ u32 r;
+
+ pr_debug("%s: %d\n", __func__, on);
+
+ if (on) {
+ gpio_set_value(GPIO_TSP_LDO_ON, 1);
+
+ r = omap4_ctrl_pad_readl(OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_I2C_0);
+ r &= ~OMAP4_I2C3_SDA_PULLUPRESX_MASK;
+ r &= ~OMAP4_I2C3_SCL_PULLUPRESX_MASK;
+ omap4_ctrl_pad_writel(r, OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_I2C_0);
+
+ omap_mux_set_gpio(OMAP_PIN_INPUT | OMAP_MUX_MODE3, GPIO_TSP_INT);
+ if (board_is_espresso10()) msleep(300);
+ } else {
+ gpio_set_value(GPIO_TSP_LDO_ON, 0);
+
+ /* Below register settings needed by prevent current leakage. */
+ r = omap4_ctrl_pad_readl(OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_I2C_0);
+ r |= OMAP4_I2C3_SDA_PULLUPRESX_MASK;
+ r |= OMAP4_I2C3_SCL_PULLUPRESX_MASK;
+ omap4_ctrl_pad_writel(r, OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_I2C_0);
+
+ omap_mux_set_gpio(OMAP_PIN_INPUT | OMAP_MUX_MODE3, GPIO_TSP_INT);
+ if (board_is_espresso10()) msleep(50);
+ }
+}
+
+const u32 espresso_tsp_fw_info = 0x17;
+
+static struct synaptics_fw_info espresso10_tsp_fw_info = {
+ .release_date = "0906",
+};
+
+static struct sec_ts_platform_data espresso_ts_pdata = {
+ .fw_name = "melfas/p3100.fw",
+ .fw_info = &espresso_tsp_fw_info,
+ .rx_channel_no = 13,
+ .tx_channel_no = 22,
+ .x_pixel_size = 1023,
+ .y_pixel_size = 599,
+ .pivot = false,
+ .ta_state = CABLE_TYPE_NONE,
+ .set_power = tsp_set_power,
+ .gpio_irq = GPIO_TSP_INT,
+ .gpio_scl = GPIO_TSP_I2C_SCL,
+ .gpio_sda = GPIO_TSP_I2C_SDA,
+};
+
+static struct i2c_board_info __initdata espresso_i2c3_boardinfo[] = {
+ {
+ I2C_BOARD_INFO("melfas_ts", 0x48),
+ .platform_data = &espresso_ts_pdata,
+ },
+};
+
+static struct i2c_board_info __initdata espresso10_i2c3_boardinfo[] = {
+ {
+ I2C_BOARD_INFO("synaptics_ts", 0x20),
+ .platform_data = &espresso_ts_pdata,
+ },
+};
+
+void touch_i2c_to_gpio(bool to_gpios)
+{
+ if (to_gpios) {
+ gpio_direction_output(GPIO_TSP_INT, 0);
+ omap_mux_set_gpio(OMAP_PIN_INPUT | OMAP_MUX_MODE3, GPIO_TSP_INT);
+
+ gpio_direction_output(GPIO_TSP_I2C_SCL, 0);
+ omap_mux_set_gpio(OMAP_PIN_INPUT | OMAP_MUX_MODE3, GPIO_TSP_I2C_SCL);
+
+ gpio_direction_output(GPIO_TSP_I2C_SDA, 0);
+ omap_mux_set_gpio(OMAP_PIN_INPUT | OMAP_MUX_MODE3, GPIO_TSP_I2C_SDA);
+ } else {
+ gpio_direction_output(GPIO_TSP_INT, 1);
+ gpio_direction_input(GPIO_TSP_INT);
+ omap_mux_set_gpio(OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE3, GPIO_TSP_INT);
+
+ gpio_direction_output(GPIO_TSP_I2C_SCL, 1);
+ gpio_direction_input(GPIO_TSP_I2C_SCL);
+ omap_mux_set_gpio(OMAP_PIN_INPUT | OMAP_MUX_MODE0, GPIO_TSP_I2C_SCL);
+
+ gpio_direction_output(GPIO_TSP_I2C_SDA, 1);
+ gpio_direction_input(GPIO_TSP_I2C_SDA);
+ omap_mux_set_gpio(OMAP_PIN_INPUT | OMAP_MUX_MODE0, GPIO_TSP_I2C_SDA);
+ }
+}
+
+static void __init espresso_gpio_keypad_gpio_init(void)
+{
+ if (board_is_espresso10()) {
+ espresso_gpio_keypad_keys_map_low[0].gpio = GPIO_VOL_UP;
+ espresso_gpio_keypad_keys_map_low[1].gpio = GPIO_VOL_DN;
+ }
+}
+
+static void __init espresso_tsp_gpio_init(void)
+{
+ struct gpio tsp_gpios[] = {
+ {
+ .flags = GPIOF_IN,
+ .gpio = GPIO_TSP_INT,
+ .label = "TSP_INT",
+ },
+ {
+ .flags = GPIOF_OUT_INIT_HIGH,
+ .gpio = GPIO_TSP_LDO_ON,
+ .label = "TSP_LDO_ON",
+ },
+ {
+ .label = "TSP_I2C_SCL_1.8V",
+ .gpio = GPIO_TSP_I2C_SCL,
+ },
+ {
+ .label = "TSP_I2C_SDA_1.8V",
+ .gpio = GPIO_TSP_I2C_SDA,
+ },
+ };
+
+ gpio_request_array(tsp_gpios, ARRAY_SIZE(tsp_gpios));
+
+ espresso_i2c3_boardinfo[0].irq = gpio_to_irq(GPIO_TSP_INT);
+ espresso10_i2c3_boardinfo[0].irq = gpio_to_irq(GPIO_TSP_INT);
+}
+
+static void __init espresso_ts_panel_setup(void)
+{
+ int i, panel_id = 0;
+ const char *panel_name[8] = { "ILJIN", "DIGITECH", "iljin", "o-film", "s-mac" };
+ struct gpio ts_panel_gpios[] = {
+ {
+ .label = "TSP_VENDOR1",
+ .gpio = GPIO_TSP_VENDOR1,
+ .flags = GPIOF_IN
+ },
+ {
+ .label = "TSP_VENDOR2",
+ .gpio = GPIO_TSP_VENDOR2,
+ .flags = GPIOF_IN
+ },
+ {
+ .label = "TSP_VENDOR3",
+ .gpio = GPIO_TSP_VENDOR3,
+ .flags = GPIOF_IN
+ },
+ };
+
+ gpio_request_array(ts_panel_gpios, ARRAY_SIZE(ts_panel_gpios));
+
+ for (i = 0; i < ARRAY_SIZE(ts_panel_gpios); i++)
+ panel_id |= gpio_get_value(ts_panel_gpios[i].gpio) << i;
+
+ if (board_is_espresso10()) {
+ espresso_ts_pdata.fw_name = "synaptics/p5100.fw";
+ espresso_ts_pdata.fw_info = &espresso10_tsp_fw_info,
+ espresso_ts_pdata.rx_channel_no = 42,
+ espresso_ts_pdata.tx_channel_no = 27,
+ espresso_ts_pdata.x_pixel_size = 1279,
+ espresso_ts_pdata.y_pixel_size = 799,
+ panel_id += 2;
+ }
+ espresso_ts_pdata.panel_name = panel_name[clamp(panel_id, 0, 7)];
+}
+
+void omap4_espresso_tsp_ta_detect(int cable_type)
+{
+ espresso_ts_pdata.ta_state = cable_type;
+
+ /* Conditions for prevent kernel panic */
+ if (espresso_ts_pdata.set_ta_mode && gpio_get_value(GPIO_TSP_LDO_ON))
+ espresso_ts_pdata.set_ta_mode(&espresso_ts_pdata.ta_state);
+}
+
+void __init omap4_espresso_input_init(void)
+{
+ espresso_gpio_keypad_gpio_init();
+ espresso_tsp_gpio_init();
+ espresso_ts_panel_setup();
+
+ if (!board_is_espresso10()) {
+ i2c_register_board_info(3, espresso_i2c3_boardinfo,
+ ARRAY_SIZE(espresso_i2c3_boardinfo));
+ } else {
+ i2c_register_board_info(3, espresso10_i2c3_boardinfo,
+ ARRAY_SIZE(espresso10_i2c3_boardinfo));
+ }
+
+ platform_device_register(&espresso_gpio_keypad_device);
+}
diff --git a/arch/arm/mach-omap2/board-espresso-irled.c b/arch/arm/mach-omap2/board-espresso-irled.c
new file mode 100644
index 0000000..e1591c0
--- /dev/null
+++ b/arch/arm/mach-omap2/board-espresso-irled.c
@@ -0,0 +1,320 @@
+/* arch/arm/mach-omap2/board-espresso-irled.c
+ *
+ * Copyright (C) 2012 Samsung Electronics Co. Ltd. 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/delay.h>
+#include <linux/gpio.h>
+#include <asm/mach-types.h>
+
+#include "mux.h"
+#include "board-espresso.h"
+
+#define GPIO_IRDA_EN 59
+#define GPIO_IRDA_CONTROL 152
+
+#define CLOCK_VALUE 800000
+#define ON_OFFSET_VALUE -2
+#define OFF_OFFSET_VALUE 0
+
+#define MAX_SIZE 1024
+#define MICRO_SEC 1000000
+
+static struct gpio irled_gpios[] = {
+ {
+ .flags = GPIOF_OUT_INIT_LOW,
+ .gpio = GPIO_IRDA_EN,
+ .label = "IRDA_EN",
+ },
+ {
+ .flags = GPIOF_OUT_INIT_LOW,
+ .gpio = GPIO_IRDA_CONTROL,
+ .label = "IRDA_CONTROL",
+ },
+};
+
+static struct irled_data {
+ struct work_struct work;
+ int cpu_frequency;
+ int on_offset;
+ int off_offset;
+ unsigned int signal[MAX_SIZE];
+} ir_data;
+
+static void irled_work(struct work_struct *work)
+{
+ unsigned int period;
+ unsigned int off_period;
+ unsigned int duty;
+ unsigned int on;
+ unsigned int off;
+ unsigned int i;
+ unsigned int j;
+
+ gpio_direction_output(GPIO_IRDA_EN, 1);
+
+ __udelay(1000);
+
+ period = (MICRO_SEC / ir_data.signal[0]) + ir_data.on_offset;
+
+ duty = period / 4;
+ on = duty;
+ off = period - duty;
+
+ local_irq_disable();
+ for (i = 1; i < MAX_SIZE; i += 2) {
+ if (ir_data.signal[i] == 0)
+ break;
+
+ for (j = 0; j < ir_data.signal[i]; j++) {
+ gpio_direction_output(GPIO_IRDA_CONTROL, 1);
+ __udelay(on);
+ gpio_direction_output(GPIO_IRDA_CONTROL, 0);
+ __udelay(off);
+ }
+
+ period = (MICRO_SEC / ir_data.signal[0]) + ir_data.off_offset;
+
+ off_period = ir_data.signal[i + 1] * period;
+
+ if (off_period <= 9999) {
+ if (off_period > 1000) {
+ __udelay(off_period % 1000);
+ mdelay(off_period / 1000);
+ } else
+ __udelay(off_period);
+ } else {
+ local_irq_enable();
+ __udelay(off_period % 1000);
+ mdelay(off_period / 1000);
+ local_irq_disable();
+ }
+ }
+ gpio_direction_output(GPIO_IRDA_CONTROL, 1);
+ __udelay(on);
+ gpio_direction_output(GPIO_IRDA_CONTROL, 0);
+ __udelay(off);
+
+ local_irq_enable();
+
+ gpio_direction_output(GPIO_IRDA_EN, 0);
+}
+
+static ssize_t irled_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ int i;
+ unsigned int _data;
+
+ for (i = 0; i < MAX_SIZE; i++) {
+ if (sscanf(buf++, "%u", &_data) == 1) {
+ ir_data.signal[i] = _data;
+ if (ir_data.signal[i] == 0)
+ break;
+ while (_data > 0) {
+ buf++;
+ _data /= 10;
+ }
+ } else {
+ ir_data.signal[i] = 0;
+ break;
+ }
+ }
+
+ if (!work_pending(&ir_data.work))
+ schedule_work(&ir_data.work);
+
+ return size;
+}
+
+static ssize_t irled_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int i;
+ char *bufp = buf;
+
+ for (i = 0; i < MAX_SIZE; i++) {
+ if (ir_data.signal[i] == 0)
+ break;
+ else {
+ bufp += sprintf(bufp, "%u,", ir_data.signal[i]);
+ pr_info("%u,", ir_data.signal[i]);
+ }
+ }
+ return strlen(buf);
+}
+
+static ssize_t check_ir_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int _data = 1;
+ return sprintf(buf, "%d\n", _data);
+}
+
+static ssize_t clock_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ unsigned int _data;
+ if (sscanf(buf, "%u", &_data) == 1)
+ if (_data == 300000 || _data == 600000 || _data == 800000
+ || _data == 1008000)
+ ir_data.cpu_frequency = _data;
+
+ return size;
+}
+
+static ssize_t clock_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ sprintf(buf, "%u\n", ir_data.cpu_frequency);
+ return strlen(buf);
+}
+
+static ssize_t on_offset_store(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t size)
+{
+ int _data;
+ if (sscanf(buf, "%d\n", &_data) == 1)
+ ir_data.on_offset = _data;
+
+ return size;
+}
+
+static ssize_t on_offset_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ sprintf(buf, "%d\n", ir_data.on_offset);
+ return strlen(buf);
+}
+
+static ssize_t off_offset_store(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t size)
+{
+ int _data;
+ if (sscanf(buf, "%d\n", &_data) == 1)
+ ir_data.off_offset = _data;
+
+ return size;
+}
+
+static ssize_t off_offset_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ sprintf(buf, "%d\n", ir_data.off_offset);
+ return strlen(buf);
+}
+
+static DEVICE_ATTR(ir_send, S_IRUGO | S_IWUSR | S_IWGRP,
+ irled_show, irled_store);
+static DEVICE_ATTR(check_ir, S_IRUGO, check_ir_show, NULL);
+
+static DEVICE_ATTR(clock, S_IRUGO | S_IWUSR | S_IWGRP, clock_show, clock_store);
+static DEVICE_ATTR(on_offset, S_IRUGO | S_IWUSR | S_IWGRP,
+ on_offset_show, on_offset_store);
+static DEVICE_ATTR(off_offset, S_IRUGO | S_IWUSR | S_IWGRP,
+ off_offset_show, off_offset_store);
+
+static int __init irled_init(void)
+{
+ int ret;
+ struct device *irled_dev;
+
+ ir_data.cpu_frequency = CLOCK_VALUE;
+ ir_data.on_offset = ON_OFFSET_VALUE;
+ ir_data.off_offset = OFF_OFFSET_VALUE;
+
+ INIT_WORK(&ir_data.work, irled_work);
+
+ irled_dev = device_create(sec_class, NULL, 0, &ir_data, "sec_ir");
+
+ if (unlikely(IS_ERR(irled_dev))) {
+ pr_err("irled: failed create irled device\n");
+ goto err_create_dev;
+ }
+
+ ret = device_create_file(irled_dev, &dev_attr_ir_send);
+ if (unlikely(ret < 0)) {
+ pr_err("irled: failed create device file\n");
+ goto err_create_dev_file1;
+ }
+
+ ret = device_create_file(irled_dev, &dev_attr_check_ir);
+ if (unlikely(ret < 0)) {
+ pr_err("irled: failed create device file\n");
+ goto err_create_dev_file2;
+ }
+
+ ret = device_create_file(irled_dev, &dev_attr_clock);
+ if (unlikely(ret < 0)) {
+ pr_err("irled: failed create device file\n");
+ goto err_create_dev_file3;
+ }
+
+ ret = device_create_file(irled_dev, &dev_attr_on_offset);
+ if (unlikely(ret < 0)) {
+ pr_err("irled: failed create device file\n");
+ goto err_create_dev_file4;
+ }
+
+ ret = device_create_file(irled_dev, &dev_attr_off_offset);
+ if (unlikely(ret < 0)) {
+ pr_err("irled: failed create device file\n");
+ goto err_create_dev_file5;
+ }
+
+ return 0;
+
+err_create_dev_file5:
+ device_remove_file(irled_dev, &dev_attr_on_offset);
+err_create_dev_file4:
+ device_remove_file(irled_dev, &dev_attr_clock);
+err_create_dev_file3:
+ device_remove_file(irled_dev, &dev_attr_check_ir);
+err_create_dev_file2:
+ device_remove_file(irled_dev, &dev_attr_ir_send);
+err_create_dev_file1:
+ device_destroy(sec_class, irled_dev->devt);
+err_create_dev:
+ return -1;
+}
+
+int __init omap4_espresso_irled_init(void)
+{
+ int ret = 0;
+ int i;
+
+ if (system_rev > 6 && !board_is_bestbuy_variant()) {
+ if (board_is_espresso10()) {
+ for (i = 0; i < ARRAY_SIZE(irled_gpios); i++) {
+ omap_mux_set_gpio(
+ OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE7,
+ irled_gpios[i].gpio);
+ }
+ }
+ return 0;
+ }
+
+ gpio_request_array(irled_gpios, ARRAY_SIZE(irled_gpios));
+
+ ret = irled_init();
+ if (ret < 0) {
+ pr_err("irled: irled_init failed\n");
+ gpio_free_array(irled_gpios, ARRAY_SIZE(irled_gpios));
+ }
+
+ return ret;
+}
+
+late_initcall(omap4_espresso_irled_init);
diff --git a/arch/arm/mach-omap2/board-espresso-jack.c b/arch/arm/mach-omap2/board-espresso-jack.c
new file mode 100644
index 0000000..89dccd0
--- /dev/null
+++ b/arch/arm/mach-omap2/board-espresso-jack.c
@@ -0,0 +1,178 @@
+/* arch/arm/mach-omap2/board-espresso-jack.c
+ *
+ * Copyright (C) 2011 Samsung Electronics Co, Ltd
+ *
+ * Based on mach-omap2/board-espresso.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/gpio.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/sec_jack.h>
+
+#include "board-espresso.h"
+
+#define ADC_CHANNEL_JACK 2
+
+static unsigned int gpio_ear_micbias_en;
+
+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 < 350, unstable zone, default to 3pole if it stays
+ * in this range for a half second (20ms delays, 25 samples)
+ */
+ .adc_high = 350,
+ .delay_ms = 20,
+ .check_count = 25,
+ .jack_type = SEC_HEADSET_3POLE,
+ },
+ {
+ /* 350 < adc <= 759, unstable zone,
+ * default to 3pole if it stays
+ * in this range for a second (10ms delays, 100 samples)
+ */
+ .adc_high = 759,
+ .delay_ms = 10,
+ .check_count = 25,
+ .jack_type = SEC_HEADSET_3POLE,
+ },
+ {
+ /* 759 < adc <= 950, unstable zone, default to 4pole if it
+ * stays in this range for a second (10ms delays, 100 samples)
+ */
+ .adc_high = 950,
+ .delay_ms = 10,
+ .check_count = 25,
+ .jack_type = SEC_HEADSET_4POLE,
+ },
+ {
+ /* 950 < adc <= 2100, 4 pole zone, default to 4pole if it
+ * stays in this range for 200ms (20ms delays, 10 samples)
+ */
+ .adc_high = 2100,
+ .delay_ms = 20,
+ .check_count = 10,
+ .jack_type = SEC_HEADSET_4POLE,
+ },
+ {
+ /* adc > 2100, 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 <= 108, stable zone */
+ .code = KEY_MEDIA,
+ .adc_low = 0,
+ .adc_high = 108,
+ },
+ {
+ /* 109 <= adc <= 250, stable zone */
+ .code = KEY_VOLUMEUP,
+ .adc_low = 109,
+ .adc_high = 250,
+ },
+ {
+ /* 251 <= adc <= 530, stable zone */
+ .code = KEY_VOLUMEDOWN,
+ .adc_low = 251,
+ .adc_high = 530,
+ },
+};
+
+static int sec_jack_get_adc_value(void)
+{
+ int value;
+ value = omap4_espresso_get_adc(EAR_ADC_35);
+ return (int)(3300*value) / 4095;
+}
+
+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),
+};
+
+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,
+};
+
+enum {
+ GPIO_DET_3_5 = 0,
+ GPIO_EAR_SEND_END,
+ GPIO_EAR_MICBIAS_EN
+};
+
+void __init omap4_espresso_jack_init(void)
+{
+ struct gpio jack_gpios[] = {
+ [GPIO_DET_3_5] = {
+ .flags = GPIOF_IN,
+ .gpio = 0,
+ .label = "DET_3.5",
+ },
+ [GPIO_EAR_SEND_END] = {
+ .flags = GPIOF_IN,
+ .gpio = 4,
+ .label = "EAR_SEND_END",
+ },
+ [GPIO_EAR_MICBIAS_EN] = {
+ .flags = GPIOF_OUT_INIT_LOW,
+ .gpio = 49,
+ .label = "EAR_MICBIAS_EN",
+ },
+ };
+
+ gpio_request_array(jack_gpios, ARRAY_SIZE(jack_gpios));
+
+ sec_jack_pdata.det_gpio = jack_gpios[GPIO_DET_3_5].gpio;
+ sec_jack_pdata.send_end_gpio = jack_gpios[GPIO_EAR_SEND_END].gpio;
+
+ // espresso10 has a slightly different setup
+ if (board_is_espresso10()) {
+ sec_jack_pdata.zones[0].adc_high = 700;
+ sec_jack_pdata.zones[1].adc_high = 1019;
+ sec_jack_pdata.zones[2].adc_high = 2000;
+ sec_jack_pdata.zones[3].adc_high = 2800;
+ sec_jack_pdata.buttons_zones[0].adc_high = 144;
+ sec_jack_pdata.buttons_zones[1].adc_low = 145;
+ sec_jack_pdata.buttons_zones[1].adc_high = 334;
+ sec_jack_pdata.buttons_zones[2].adc_low = 335;
+ sec_jack_pdata.buttons_zones[2].adc_high = 705;
+ }
+
+ gpio_ear_micbias_en = jack_gpios[GPIO_EAR_MICBIAS_EN].gpio;
+
+ gpio_free(sec_jack_pdata.det_gpio);
+ gpio_free(sec_jack_pdata.send_end_gpio);
+
+ platform_device_register(&sec_device_jack);
+}
diff --git a/arch/arm/mach-omap2/board-espresso-modems.c b/arch/arm/mach-omap2/board-espresso-modems.c
new file mode 100644
index 0000000..b24ed19
--- /dev/null
+++ b/arch/arm/mach-omap2/board-espresso-modems.c
@@ -0,0 +1,285 @@
+/* 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_v2.h>
+
+#include "board-espresso.h"
+#include "mux.h"
+
+/* 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,
+ .links = LINKTYPE(LINKDEV_MIPI),
+ },
+ [1] = {
+ .name = "umts_rfs0",
+ .id = 0x41,
+ .format = IPC_RFS,
+ .io_type = IODEV_MISC,
+ .links = LINKTYPE(LINKDEV_MIPI),
+ },
+ [2] = {
+ .name = "rmnet0",
+ .id = 0x2A,
+ .format = IPC_RAW,
+ .io_type = IODEV_NET,
+ .links = LINKTYPE(LINKDEV_MIPI),
+ },
+ [3] = {
+ .name = "umts_boot0",
+ .id = 0x0,
+ .format = IPC_BOOT,
+ .io_type = IODEV_MISC,
+ .links = LINKTYPE(LINKDEV_MIPI),
+ },
+ [4] = {
+ .name = "rmnet1",
+ .id = 0x2B,
+ .format = IPC_RAW,
+ .io_type = IODEV_NET,
+ .links = LINKTYPE(LINKDEV_MIPI),
+ },
+ [5] = {
+ .name = "rmnet2",
+ .id = 0x2C,
+ .format = IPC_RAW,
+ .io_type = IODEV_NET,
+ .links = LINKTYPE(LINKDEV_MIPI),
+ },
+ [6] = {
+ .name = "multipdp",
+ .id = 0x1,
+ .format = IPC_MULTI_RAW,
+ .io_type = IODEV_DUMMY,
+ .links = LINKTYPE(LINKDEV_MIPI),
+ },
+ [7] = {
+ .name = "umts_ramdump0",
+ .id = 0x0,
+ .format = IPC_RAMDUMP,
+ .io_type = IODEV_MISC,
+ .links = LINKTYPE(LINKDEV_MIPI),
+ },
+ [8] = {
+ .name = "umts_boot1",
+ .id = 0x0,
+ .format = IPC_BOOT_2,
+ .io_type = IODEV_MISC,
+ .links = LINKTYPE(LINKDEV_MIPI),
+ },
+ [9] = {
+ .name = "umts_router", /* AT Iface & Dial-up */
+ .id = 0x39,
+ .format = IPC_RAW,
+ .io_type = IODEV_MISC,
+ .links = LINKTYPE(LINKDEV_MIPI),
+ },
+ [10] = {
+ .name = "umts_csd",
+ .id = 0x21,
+ .format = IPC_RAW,
+ .io_type = IODEV_MISC,
+ .links = LINKTYPE(LINKDEV_MIPI),
+ },
+ [11] = {
+ .name = "umts_loopback0",
+ .id = 0x3F,
+ .format = IPC_RAW,
+ .io_type = IODEV_MISC,
+ .links = LINKTYPE(LINKDEV_MIPI),
+ },
+};
+
+#define GPIO_CP_ON 37
+#define GPIO_CP_PMU_RST 39
+#define GPIO_CP_PMU_RST_OLDREV 2
+#define GPIO_RESET_REQ_N 50
+#define GPIO_PDA_ACTIVE 119
+#define GPIO_PHONE_ACTIVE 120
+#define GPIO_CP_DUMP_INT 56
+#define GPIO_SIM_DETECT 35
+
+struct gpio modem_gpios[] __initdata = {
+ {
+ .flags = GPIOF_OUT_INIT_LOW,
+ .gpio = GPIO_CP_ON,
+ .label = "CP_ON",
+ },
+ {
+ .flags = GPIOF_OUT_INIT_LOW,
+ .gpio = GPIO_CP_PMU_RST,
+ .label = "CP_PMU_RST",
+ },
+ {
+ .flags = GPIOF_OUT_INIT_LOW,
+ .gpio = GPIO_RESET_REQ_N,
+ .label = "RESET_REQ_N",
+ },
+ {
+ .flags = GPIOF_OUT_INIT_LOW,
+ .gpio = GPIO_PDA_ACTIVE,
+ .label = "PDA_ACTIVE",
+ },
+ {
+ .flags = GPIOF_IN,
+ .gpio = GPIO_PHONE_ACTIVE,
+ .label = "PHONE_ACTIVE",
+ },
+ {
+ .flags = GPIOF_IN,
+ .gpio = GPIO_CP_DUMP_INT,
+ .label = "CP_DUMP_INT",
+ },
+ {
+ .flags = GPIOF_IN,
+ .gpio = GPIO_SIM_DETECT,
+ .label = "SIM_DETECT",
+ },
+};
+
+static struct omap_board_mux mux_none_modem[] __initdata = {
+ /* [-N-C-] usbb1_ulpitll_stp - gpio_85 - MIPI_HSI_TX_DATA */
+ OMAP4_MUX(USBB1_ULPITLL_STP,
+ OMAP_MUX_MODE7 | OMAP_PIN_INPUT_PULLDOWN),
+ /* [-N-C-] usbb1_ulpitll_dir - gpio_86 - MIPI_HSI_TX_FLG */
+ OMAP4_MUX(USBB1_ULPITLL_DIR,
+ OMAP_MUX_MODE7 | OMAP_PIN_INPUT_PULLDOWN),
+ /* [-N-C-] usbb1_ulpitll_nxt - gpio_87 - MIPI_HSI_TX_RDY */
+ OMAP4_MUX(USBB1_ULPITLL_NXT,
+ OMAP_MUX_MODE7 | OMAP_PIN_INPUT_PULLDOWN),
+ /* [-N-C-] usbb1_ulpitll_dat0 - gpio_88 - MIPI_HSI_RX_WAKE */
+ OMAP4_MUX(USBB1_ULPITLL_DAT0,
+ OMAP_MUX_MODE7 | OMAP_PIN_INPUT_PULLDOWN),
+ /* [-N-C-] usbb1_ulpitll_dat1 - gpio_89 - MIPI_HSI_RX_DATA */
+ OMAP4_MUX(USBB1_ULPITLL_DAT1,
+ OMAP_MUX_MODE7 | OMAP_PIN_INPUT_PULLDOWN),
+ /* [-N-C-] usbb1_ulpitll_dat2 - gpio_90 - MIPI_HSI_RX_FLG */
+ OMAP4_MUX(USBB1_ULPITLL_DAT2,
+ OMAP_MUX_MODE7 | OMAP_PIN_INPUT_PULLDOWN),
+ /* [-N-C-] usbb1_ulpitll_dat3 - gpio_91 - MIPI_HSI_RX_RDY */
+ OMAP4_MUX(USBB1_ULPITLL_DAT3,
+ OMAP_MUX_MODE7 | OMAP_PIN_INPUT_PULLDOWN),
+ /* [--OUT] gpmc_ncs0.gpio_50 - RESET_REQ_N */
+ OMAP4_MUX(GPMC_NCS0,
+ OMAP_MUX_MODE7 | OMAP_PIN_INPUT_PULLDOWN),
+ /* [--OUT] abe_dmic_clk1.gpio_119 - PDA_ACTIVE */
+ OMAP4_MUX(ABE_DMIC_CLK1,
+ OMAP_MUX_MODE7 | OMAP_PIN_INPUT_PULLDOWN),
+ /* [IN---] abe_dmic_din1.gpio_120 - PHONE_ACTIVE */
+ OMAP4_MUX(ABE_DMIC_DIN1,
+ OMAP_MUX_MODE7 | OMAP_PIN_INPUT_PULLDOWN),
+ /* [IN---] gpmc_nadv_ale.gpio_56 - CP_DUMP_INT */
+ OMAP4_MUX(GPMC_NADV_ALE,
+ OMAP_MUX_MODE7 | OMAP_PIN_INPUT_PULLDOWN),
+ /* [IN---] gpmc_ad11.gpio_35 - SIM_DETECT */
+ OMAP4_MUX(GPMC_AD11,
+ OMAP_MUX_MODE7 | OMAP_PIN_INPUT_PULLDOWN),
+ /* [--OUT] gpmc_ad13.gpio_37 - CP_ON */
+ OMAP4_MUX(GPMC_AD13,
+ OMAP_MUX_MODE7 | OMAP_PIN_INPUT_PULLDOWN),
+ { .reg_offset = OMAP_MUX_TERMINATOR },
+};
+
+static struct modem_data umts_modem_data = {
+ .name = "xmm6262",
+
+ .modem_type = IMC_XMM6262,
+ .link_types = LINKTYPE(LINKDEV_MIPI),
+ .use_handover = false,
+ .num_iodevs = ARRAY_SIZE(umts_io_devices),
+ .iodevs = umts_io_devices,
+
+ .gpio_cp_on = GPIO_CP_ON,
+ .gpio_reset_req_n = GPIO_RESET_REQ_N,
+ .gpio_cp_reset = GPIO_CP_PMU_RST,
+ .gpio_pda_active = GPIO_PDA_ACTIVE,
+ .gpio_phone_active = GPIO_PHONE_ACTIVE,
+ .gpio_cp_dump_int = GPIO_CP_DUMP_INT,
+};
+
+static void __init umts_modem_cfg_gpio(void)
+{
+ if ((board_is_espresso10() && system_rev < 8) ||
+ (!board_is_espresso10() && system_rev < 10)) {
+ modem_gpios[1].gpio = GPIO_CP_PMU_RST_OLDREV;
+ umts_modem_data.gpio_cp_reset = GPIO_CP_PMU_RST_OLDREV;
+ }
+
+ gpio_request_array(modem_gpios, ARRAY_SIZE(modem_gpios));
+
+ if (!board_is_espresso10()) {
+ umts_modem_data.gpio_sim_detect = GPIO_SIM_DETECT;
+ }
+
+ pr_debug("umts_modem_cfg_gpio done\n");
+}
+
+static void __init none_modem_cfg_mux(void)
+{
+ struct omap_mux_partition *core = omap_mux_get("core");
+ struct omap_mux_partition *wkup = omap_mux_get("wkup");
+
+ omap_mux_write_array(core, mux_none_modem);
+
+ if ((board_is_espresso10() && system_rev < 8) ||
+ (!board_is_espresso10() && system_rev < 10)) {
+ omap_mux_write(wkup,
+ OMAP_MUX_MODE7 | OMAP_PIN_INPUT_PULLDOWN,
+ OMAP4_CTRL_MODULE_PAD_SIM_RESET_OFFSET);
+ } else {
+ omap_mux_write(core,
+ OMAP_MUX_MODE7 | OMAP_PIN_INPUT_PULLDOWN,
+ OMAP4_CTRL_MODULE_PAD_GPMC_AD15_OFFSET);
+ }
+}
+
+static struct platform_device umts_modem = {
+ .name = "mif_sipc4",
+ .id = -1,
+ .dev = {
+ .platform_data = &umts_modem_data,
+ },
+};
+
+void __init omap4_espresso_none_modem_init(void)
+{
+ if (!board_has_modem())
+ none_modem_cfg_mux();
+}
+
+static int __init init_modem(void)
+{
+ if (!board_has_modem())
+ return 0;
+
+ umts_modem_cfg_gpio();
+ platform_device_register(&umts_modem);
+
+ mif_info("board init_modem done\n");
+ return 0;
+}
+late_initcall(init_modem);
diff --git a/arch/arm/mach-omap2/board-espresso-pmic.c b/arch/arm/mach-omap2/board-espresso-pmic.c
new file mode 100644
index 0000000..fa438e3
--- /dev/null
+++ b/arch/arm/mach-omap2/board-espresso-pmic.c
@@ -0,0 +1,617 @@
+/* arch/arm/mach-omap2/board-espresso-pmic.c
+ *
+ * Copyright (C) 2011 Samsung Electronics Co, Ltd.
+ *
+ * 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/i2c.h>
+#include <linux/i2c/twl.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/fixed.h>
+
+#ifdef CONFIG_SND_OMAP_SOC_ESPRESSO
+#include <linux/mfd/wm8994/pdata.h>
+#include <linux/mfd/wm8994/gpio.h>
+#endif
+
+#include <plat/omap-pm.h>
+#include "pm.h"
+
+#include "board-espresso.h"
+#include "common-board-devices.h"
+
+#define GPIO_EMMC_EN 53
+#define GPIO_CODEC_LDO_EN 45
+#define GPIO_SYS_DRM_MSEC 6
+#define GPIO_TF_EN 34
+
+#define GPIO_SUB_MICBIAS_EN 177
+#define GPIO_CODEC_CLK_REQ 101
+#define GPIO_MICBIAS_EN 48
+#define GPIO_EAR_GND_SEL 171
+
+#define TWL6030_BBSPOR_CFG 0xE6
+#define TWL6030_PHOENIX_MSK_TRANSITION 0x20
+
+#define TWL_REG_CONTROLLER_INT_MASK 0x00
+#define TWL_CONTROLLER_MVBUS_DET (1 << 1)
+#define TWL_CONTROLLER_RSVD (1 << 5)
+
+#define TWL6030_PHEONIX_MSK_TRANS_SHIFT 0x05
+
+#define TWL_BBSPOR_CFG_VRTC_PWEN (1 << 4)
+#define TWL_BBSPOR_CFG_VRTC_EN_OFF_STS (1 << 5)
+#define TWL_BBSPOR_CFG_VRTC_EN_SLP_STS (1 << 6)
+
+#define TWL6030_CFG_LDO_PD2 0xF5
+
+static bool enable_sr = true;
+module_param(enable_sr, bool, S_IRUSR | S_IRGRP | S_IROTH);
+
+#ifdef CONFIG_SND_OMAP_SOC_ESPRESSO
+static struct regulator_consumer_supply vbatt_supplies[] = {
+ REGULATOR_SUPPLY("LDO1VDD", "1-001a"),
+ REGULATOR_SUPPLY("SPKVDD1", "1-001a"),
+ REGULATOR_SUPPLY("SPKVDD2", "1-001a"),
+ REGULATOR_SUPPLY("AVDD2", "1-001a"),
+ REGULATOR_SUPPLY("CPVDD", "1-001a"),
+ REGULATOR_SUPPLY("DBVDD1", "1-001a"),
+ REGULATOR_SUPPLY("DBVDD2", "1-001a"),
+ REGULATOR_SUPPLY("DBVDD3", "1-001a"),
+};
+
+static struct regulator_init_data vbatt_initdata = {
+ .constraints = {
+ .always_on = true,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(vbatt_supplies),
+ .consumer_supplies = vbatt_supplies,
+};
+
+static struct fixed_voltage_config vbatt_config = {
+ .init_data = &vbatt_initdata,
+ .microvolts = 1800000,
+ .supply_name = "VBATT",
+ .gpio = -EINVAL,
+};
+
+static struct platform_device vbatt_device = {
+ .name = "reg-fixed-voltage",
+ .id = -1,
+ .dev = {
+ .platform_data = &vbatt_config,
+ },
+};
+
+static struct regulator_consumer_supply wm1811_ldo1_supplies[] = {
+ REGULATOR_SUPPLY("AVDD1", "1-001a"),
+};
+
+static struct regulator_init_data wm1811_ldo1_initdata = {
+ .constraints = {
+ .name = "WM1811 LDO1",
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(wm1811_ldo1_supplies),
+ .consumer_supplies = wm1811_ldo1_supplies,
+};
+
+static struct regulator_consumer_supply wm1811_ldo2_supplies[] = {
+ REGULATOR_SUPPLY("DCVDD", "1-001a"),
+};
+
+static struct regulator_init_data wm1811_ldo2_initdata = {
+ .constraints = {
+ .name = "WM1811 LDO2",
+ .always_on = true, /* Actually status changed by LDO1 */
+ },
+ .num_consumer_supplies = ARRAY_SIZE(wm1811_ldo2_supplies),
+ .consumer_supplies = wm1811_ldo2_supplies,
+};
+
+static struct wm8994_pdata wm1811_pdata = {
+ .gpio_defaults = {
+ [0] = WM8994_GP_FN_IRQ,
+ [7] = WM8994_GPN_DIR | WM8994_GP_FN_PIN_SPECIFIC,
+ [8] = WM8994_CONFIGURE_GPIO | WM8994_GP_FN_PIN_SPECIFIC,
+ [9] = WM8994_CONFIGURE_GPIO | WM8994_GP_FN_PIN_SPECIFIC,
+ [10] = WM8994_CONFIGURE_GPIO | WM8994_GP_FN_PIN_SPECIFIC,
+ },
+
+ /* for using wm1811 jack detect
+ * This line should be remained for next board */
+ /*.irq_base = TWL6040_CODEC_IRQ_BASE,*/
+
+ .ldo = {
+ {
+ .init_data = &wm1811_ldo1_initdata,
+ .enable = GPIO_CODEC_LDO_EN,
+ },
+ {
+ .init_data = &wm1811_ldo2_initdata,
+ }
+ },
+
+ /* Regulated mode at highest output voltage */
+ .micbias = { 0x2f, 0x29 },
+
+ .ldo_ena_always_driven = true,
+
+ .ear_select_gpio = GPIO_EAR_GND_SEL,
+ .main_mic_bias_gpio = GPIO_MICBIAS_EN,
+ .mclk_gpio = GPIO_CODEC_CLK_REQ,
+};
+#endif
+
+static struct regulator_init_data espresso_vaux1 = {
+ .constraints = {
+ .min_uV = 2800000,
+ .max_uV = 2800000,
+ .apply_uV = true,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL
+ | REGULATOR_MODE_STANDBY,
+ .valid_ops_mask = REGULATOR_CHANGE_MODE
+ | REGULATOR_CHANGE_STATUS,
+ .state_mem = {
+ .disabled = true,
+ },
+ },
+};
+
+static struct regulator_consumer_supply espresso_vaux2_supplies[] = {
+ REGULATOR_SUPPLY("VAP_IO_2.8V", NULL),
+ REGULATOR_SUPPLY("SENSOR_2.8V", "4-0018"),
+ REGULATOR_SUPPLY("SENSOR_2.8V", "4-0044"),
+};
+
+static struct regulator_init_data espresso_vaux2 = {
+ .constraints = {
+ .min_uV = 2800000,
+ .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,
+ .state_mem = {
+ .disabled = true,
+ },
+ },
+ .num_consumer_supplies = ARRAY_SIZE(espresso_vaux2_supplies),
+ .consumer_supplies = espresso_vaux2_supplies,
+};
+
+static struct regulator_consumer_supply espresso_vmmc_supply[] = {
+ REGULATOR_SUPPLY("vmmc", "omap_hsmmc.0"),
+};
+
+static struct regulator_init_data espresso_vmmc = {
+ .constraints = {
+ .min_uV = 1200000,
+ .max_uV = 3000000,
+ .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(espresso_vmmc_supply),
+ .consumer_supplies = espresso_vmmc_supply,
+};
+
+static struct regulator_init_data espresso_vusim = {
+ .constraints = {
+ .min_uV = 3300000,
+ .max_uV = 3300000,
+ .apply_uV = true,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL
+ | REGULATOR_MODE_STANDBY,
+ .valid_ops_mask = REGULATOR_CHANGE_MODE
+ | REGULATOR_CHANGE_STATUS,
+ .always_on = true,
+ .state_mem = {
+ .enabled = true,
+ },
+ },
+};
+
+static struct regulator_init_data espresso_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,
+ .state_mem = {
+ .disabled = true,
+ },
+ },
+};
+
+static struct regulator_consumer_supply espresso_vcxio_supply[] = {
+ REGULATOR_SUPPLY("vdds_dsi", "omapdss_dss"),
+ REGULATOR_SUPPLY("vdds_dsi", "omapdss_dsi1"),
+};
+
+static struct regulator_init_data espresso_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,
+ .always_on = true,
+ .state_mem = {
+ .disabled = true,
+ },
+ },
+ .num_consumer_supplies = ARRAY_SIZE(espresso_vcxio_supply),
+ .consumer_supplies = espresso_vcxio_supply,
+};
+
+static struct regulator_consumer_supply espresso_vusb_supply[] = {
+ REGULATOR_SUPPLY("vusb", "espresso_otg"),
+};
+
+static struct regulator_init_data espresso_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,
+ .state_mem = {
+ .disabled = true,
+ },
+ },
+ .num_consumer_supplies = ARRAY_SIZE(espresso_vusb_supply),
+ .consumer_supplies = espresso_vusb_supply,
+};
+
+static struct regulator_init_data espresso_clk32kg = {
+ .constraints = {
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ .always_on = true,
+ },
+};
+
+static struct regulator_init_data espresso_clk32kaudio = {
+ .constraints = {
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ .always_on = true,
+ },
+};
+
+static struct twl4030_madc_platform_data espresso_madc = {
+ .irq_line = -1,
+ .features = TWL6032_SUBCLASS,
+};
+
+static struct platform_device espresso_madc_device = {
+ .name = "twl6030_madc",
+ .id = -1,
+ .dev = {
+ .platform_data = &espresso_madc,
+ },
+};
+
+static void espresso_twl6030_init(void)
+{
+ int ret;
+ u8 val;
+
+ /*
+ * If disable GPADC_IN1, BAT_TEMP_OVRANGE interrupt is signaled.
+ * Disable all interrupt of charger block except VBUS_DET.
+ * We need only VBUS_DET interrupt of charger block fot usb otg.
+ */
+ val = ~(TWL_CONTROLLER_RSVD | TWL_CONTROLLER_MVBUS_DET);
+ ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE, val,
+ TWL_REG_CONTROLLER_INT_MASK);
+
+ ret |= twl6030_interrupt_unmask(TWL6030_CHARGER_CTRL_INT_MASK,
+ REG_INT_MSK_LINE_C);
+
+ if (ret)
+ pr_err("%s: disable charger interrupt fail!\n", __func__);
+
+ /* use only preq1 of twl6032 */
+ ret = twl_i2c_write_u8(TWL6030_MODULE_ID0,
+ ~(DEV_GRP_P1) << TWL6030_PHEONIX_MSK_TRANS_SHIFT,
+ TWL6030_PHOENIX_MSK_TRANSITION);
+ if (ret)
+ pr_err("%s: PHOENIX_MSK_TRANSITION write fail!\n", __func__);
+
+
+ if (board_is_espresso10()) {
+ /*
+ * Enable charge backup battery and set charging voltage to 2.6V.
+ * Set VRTC low power mode in off/sleep and standard power mode in on.
+ */
+ val = TWL_BBSPOR_CFG_VRTC_EN_SLP_STS | TWL_BBSPOR_CFG_VRTC_EN_OFF_STS |
+ TWL_BBSPOR_CFG_VRTC_PWEN;
+ } else {
+ ret = twl_i2c_read_u8(TWL6030_MODULE_ID0,
+ &val, TWL6030_BBSPOR_CFG);
+
+ /* disable backup battery charge */
+ val &= ~(1 << 3);
+
+ /* configure in low power mode */
+ val |= (1 << 6 | 1 << 5);
+ }
+
+ ret = twl_i2c_write_u8(TWL6030_MODULE_ID0, val,
+ TWL6030_BBSPOR_CFG);
+ if (ret)
+ pr_err("%s: TWL6030 BBSPOR_CFG write fail!\n", __func__);
+
+
+ if (system_rev >= 8) {
+ ret = twl_i2c_read_u8(TWL6030_MODULE_ID0,
+ &val, TWL6030_CFG_LDO_PD2);
+
+ /* TI recommand
+ * recommended to leave vpp_cust turn off(float).
+ * disable internal pull-down when vpp_cust is turned off
+ */
+ val &= ~(1<<1); /*LDO7*/
+ ret |= twl_i2c_write_u8(TWL6030_MODULE_ID0,
+ val, TWL6030_CFG_LDO_PD2);
+ if (ret)
+ pr_err("%s:TWL6030 CFG_LDO_PD2 write fail!\n",
+ __func__);
+ }
+}
+
+static struct twl4030_resconfig espresso_rconfig[] = {
+ { .resource = RES_LDO2, .devgroup = 0, },
+ { .resource = RES_LDO7, .devgroup = 0, },
+ { .resource = RES_LDOLN, .devgroup = 0, },
+ { .resource = TWL4030_RESCONFIG_UNDEF, 0},
+};
+
+static struct twl4030_power_data espresso_power_data = {
+ .twl4030_board_init = espresso_twl6030_init,
+ .resource_config = espresso_rconfig,
+};
+
+static struct regulator_init_data espresso_ldo2_nc = {
+ .constraints = {
+ .min_uV = 1000000,
+ .max_uV = 3300000,
+ .apply_uV = true,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL
+ | REGULATOR_MODE_STANDBY,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE
+ | REGULATOR_CHANGE_MODE
+ | REGULATOR_CHANGE_STATUS,
+ .state_mem = {
+ .disabled = true,
+ },
+ },
+};
+
+static struct regulator_init_data espresso_ldo7_nc = {
+ .constraints = {
+ .min_uV = 1000000,
+ .max_uV = 3300000,
+ .apply_uV = true,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL
+ | REGULATOR_MODE_STANDBY,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE
+ | REGULATOR_CHANGE_MODE
+ | REGULATOR_CHANGE_STATUS,
+ .state_mem = {
+ .disabled = true,
+ },
+ },
+};
+
+static struct regulator_init_data espresso_ldoln_nc = {
+ .constraints = {
+ .min_uV = 1000000,
+ .max_uV = 3300000,
+ .apply_uV = true,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL
+ | REGULATOR_MODE_STANDBY,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE
+ | REGULATOR_CHANGE_MODE
+ | REGULATOR_CHANGE_STATUS,
+ .state_mem = {
+ .disabled = true,
+ },
+ },
+};
+
+struct twl4030_rtc_data espresso_rtc = {
+ .auto_comp = 1,
+ .comp_value = -3200,
+};
+
+static struct regulator_consumer_supply espresso_vdd_io_1V8_supplies[] = {
+ REGULATOR_SUPPLY("VDD_IO_1.8V", NULL),
+ REGULATOR_SUPPLY("SENSOR_1.8V", "4-0018"),
+ REGULATOR_SUPPLY("SENSOR_1.8V", "4-0044"),
+};
+
+static struct regulator_init_data espresso_ldo5 = {
+ .constraints = {
+ .min_uV = 1800000,
+ .max_uV = 1800000,
+ .apply_uV = true,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL
+ | REGULATOR_MODE_STANDBY,
+ .valid_ops_mask = REGULATOR_CHANGE_MODE
+ | REGULATOR_CHANGE_STATUS,
+ .state_mem = {
+ .disabled = true,
+ },
+ },
+ .num_consumer_supplies = ARRAY_SIZE(espresso_vdd_io_1V8_supplies),
+ .consumer_supplies = espresso_vdd_io_1V8_supplies,
+};
+
+static struct twl4030_platform_data espresso_twl6032_pdata = {
+ .irq_base = TWL6030_IRQ_BASE,
+ .irq_end = TWL6030_IRQ_END,
+
+ /* pmic power data*/
+ .power = &espresso_power_data,
+
+ /* TWL6025 LDO regulators */
+ .vana = &espresso_vana,
+ .ldo1 = &espresso_vaux1,
+ .ldo2 = &espresso_ldo2_nc,
+ .ldo3 = &espresso_vusim,
+ .ldo4 = &espresso_vaux2,
+ .ldo5 = &espresso_ldo5,
+ .ldo6 = &espresso_vcxio,
+ .ldo7 = &espresso_ldo7_nc,
+ .ldoln = &espresso_ldoln_nc,
+ .ldousb = &espresso_vusb,
+ .clk32kg = &espresso_clk32kg,
+ .clk32kaudio = &espresso_clk32kaudio,
+
+ /* children */
+ .madc = &espresso_madc,
+};
+
+static struct platform_device *espresso_pmic_devices[] __initdata = {
+ &espresso_madc_device,
+};
+
+static struct i2c_board_info espresso_twl6032_i2c1_board_info[] __initdata = {
+ {
+ I2C_BOARD_INFO("twl6032", 0x48),
+ .flags = I2C_CLIENT_WAKE,
+ .irq = OMAP44XX_IRQ_SYS_1N,
+ .platform_data = &espresso_twl6032_pdata,
+ },
+#ifdef CONFIG_SND_OMAP_SOC_ESPRESSO
+ {
+ I2C_BOARD_INFO("wm1811", 0x34>>1),
+ .platform_data = &wm1811_pdata,
+ }
+#endif
+};
+
+static struct fixed_voltage_config espresso_vmmc_config = {
+ .supply_name = "vmmc",
+ .microvolts = 2800000, /* 2.8V */
+ .gpio = GPIO_TF_EN,
+ .startup_delay = 0,
+ .enable_high = 1,
+ .enabled_at_boot = 0,
+ .init_data = &espresso_vmmc,
+};
+
+static struct platform_device espresso_vmmc_device = {
+ .name = "reg-fixed-voltage",
+ .id = 2,
+ .dev = {
+ .platform_data = &espresso_vmmc_config,
+ },
+};
+
+static struct regulator_consumer_supply espresso_vmmc_external_supplies = {
+ .supply = "vmmc",
+ .dev_name = "omap_hsmmc.1",
+};
+
+static struct regulator_init_data espresso_vmmc_external_data = {
+ .constraints = {
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = 1,
+ .consumer_supplies = &espresso_vmmc_external_supplies,
+};
+
+static struct fixed_voltage_config espresso_vmmc_external = {
+ .supply_name = "eMMC_LDO",
+ .gpio = GPIO_EMMC_EN,
+ .microvolts = 1800000, /* 1.8V */
+ .startup_delay = 100000, /* 100 ms */
+ .enable_high = 1,
+ .enabled_at_boot = 1,
+ .init_data = &espresso_vmmc_external_data,
+};
+
+static struct platform_device espresso_vmmc_external_device = {
+ .name = "reg-fixed-voltage",
+ .id = 3,
+ .dev = {
+ .platform_data = &espresso_vmmc_external,
+ },
+};
+
+static void __init espresso_audio_init(void)
+{
+#ifdef CONFIG_SND_OMAP_SOC_ESPRESSO
+ platform_device_register(&vbatt_device);
+
+ if (!board_is_espresso10()) {
+ wm1811_pdata.use_submic = true;
+ wm1811_pdata.submic_gpio = GPIO_SUB_MICBIAS_EN;
+ }
+#endif
+}
+
+void __init omap4_espresso_pmic_init(void)
+{
+ /* Update oscillator information */
+ omap_pm_set_osc_lp_time(15000, 1);
+
+ /*
+ * 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();
+
+ if (board_is_espresso10())
+ espresso_twl6032_pdata.rtc = &espresso_rtc;
+
+ espresso_audio_init();
+
+ platform_add_devices(espresso_pmic_devices,
+ ARRAY_SIZE(espresso_pmic_devices));
+
+ i2c_register_board_info(1, espresso_twl6032_i2c1_board_info,
+ ARRAY_SIZE(espresso_twl6032_i2c1_board_info));
+
+ /*
+ * Register fixed regulators to control external LDO.
+ */
+ platform_device_register(&espresso_vmmc_device);
+ platform_device_register(&espresso_vmmc_external_device);
+
+ /*
+ * Drive MSECURE high for TWL6030 write access.
+ */
+ gpio_request(GPIO_SYS_DRM_MSEC, "SYS_DRM_MSEC");
+ gpio_direction_output(GPIO_SYS_DRM_MSEC, 1);
+
+ if (enable_sr)
+ omap_enable_smartreflex_on_init();
+
+ /* enable off-mode */
+ omap_pm_enable_off_mode();
+}
diff --git a/arch/arm/mach-omap2/board-espresso-power.c b/arch/arm/mach-omap2/board-espresso-power.c
new file mode 100644
index 0000000..c7de5a0
--- /dev/null
+++ b/arch/arm/mach-omap2/board-espresso-power.c
@@ -0,0 +1,464 @@
+/* Power support for Samsung Gerry Board.
+ *
+ * Copyright (C) 2011 SAMSUNG, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/suspend.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/i2c-gpio.h>
+#include <linux/i2c/twl.h>
+#include <linux/power/smb_charger.h>
+#include <linux/power/max17042_battery_manager.h>
+#include <linux/bat_manager.h>
+#include <linux/battery.h>
+#include <linux/irq.h>
+
+#include "board-espresso.h"
+
+#define GPIO_TA_NCONNECTED 32
+#define GPIO_TA_NCHG 142
+#define GPIO_TA_EN 13
+#define GPIO_FUEL_ALERT 44
+
+#define GPIO_CHG_SDA 98
+#define GPIO_CHG_SCL 99
+#define GPIO_FUEL_SDA 62
+#define GPIO_FUEL_SCL 61
+
+#define CHARGER_STATUS_FULL 0x1
+
+#define CABLE_DETECT_VALUE 1150
+#define HIGH_BLOCK_TEMP 500
+#define HIGH_RECOVER_TEMP 420
+#define LOW_BLOCK_TEMP (-50)
+#define LOW_RECOVER_TEMP 0
+
+u32 bootmode;
+struct max17042_fuelgauge_callbacks *fuelgauge_callback;
+struct smb_charger_callbacks *espresso_charger_callbacks;
+struct battery_manager_callbacks *batman_callback;
+
+static irqreturn_t charger_state_isr(int irq, void *_data)
+{
+ int res = 0, val;
+
+ val = gpio_get_value(GPIO_TA_NCHG);
+
+ irq_set_irq_type(irq, val ? IRQF_TRIGGER_LOW : IRQF_TRIGGER_HIGH);
+
+ if (val) {
+ if (espresso_charger_callbacks && espresso_charger_callbacks->get_status_reg)
+ res = espresso_charger_callbacks->
+ get_status_reg(espresso_charger_callbacks);
+
+ if (res == CHARGER_STATUS_FULL && batman_callback &&
+ batman_callback->set_full_charge)
+ batman_callback->set_full_charge(batman_callback);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t fuel_alert_isr(int irq, void *_data)
+{
+ int val;
+
+ val = gpio_get_value(GPIO_FUEL_ALERT);
+ pr_info("%s: fuel alert interrupt occured : %d\n", __func__, val);
+
+ if (batman_callback && batman_callback->fuel_alert_lowbat)
+ batman_callback->fuel_alert_lowbat(batman_callback);
+
+ return IRQ_HANDLED;
+}
+
+static void charger_gpio_init(void)
+{
+ int irq, fuel_irq;
+ int ret;
+ struct gpio charger_gpios[] = {
+ {
+ .flags = GPIOF_IN,
+ .gpio = GPIO_TA_NCHG,
+ .label = "TA_nCHG"
+ },
+ {
+ .flags = GPIOF_OUT_INIT_LOW,
+ .gpio = GPIO_TA_EN,
+ .label = "TA_EN"
+ },
+ {
+ .flags = GPIOF_IN,
+ .gpio = GPIO_FUEL_ALERT,
+ .label = "FUEL_ALERT"
+ },
+ };
+
+ gpio_request_array(charger_gpios, ARRAY_SIZE(charger_gpios));
+
+ irq = gpio_to_irq(GPIO_TA_NCHG);
+ ret = request_threaded_irq(irq, NULL, charger_state_isr,
+ IRQF_TRIGGER_LOW | IRQF_ONESHOT | IRQF_NO_SUSPEND,
+ "Charge_Status", NULL);
+ if (unlikely(ret < 0))
+ pr_err("%s: request irq %d failed for gpio %d\n",
+ __func__, irq, GPIO_TA_NCHG);
+
+ fuel_irq = gpio_to_irq(GPIO_FUEL_ALERT);
+ ret = request_threaded_irq(fuel_irq, NULL, fuel_alert_isr,
+ IRQF_TRIGGER_FALLING,
+ "Fuel Alert irq", NULL);
+ if (unlikely(ret < 0))
+ pr_err("%s: request fuel alert irq %d failed for gpio %d\n",
+ __func__, fuel_irq, GPIO_FUEL_ALERT);
+}
+
+static void charger_enble_set(int state)
+{
+ gpio_set_value(GPIO_TA_EN, !state);
+ pr_debug("%s: Set charge status: %d, current status: %d\n",
+ __func__, state, !state);
+}
+
+static struct i2c_gpio_platform_data espresso_gpio_i2c5_pdata = {
+ .udelay = 10,
+ .timeout = 0,
+ .sda_pin = GPIO_CHG_SDA,
+ .scl_pin = GPIO_CHG_SCL,
+};
+
+static struct platform_device espresso_gpio_i2c5_device = {
+ .name = "i2c-gpio",
+ .id = 5,
+ .dev = {
+ .platform_data = &espresso_gpio_i2c5_pdata,
+ }
+};
+
+static struct i2c_gpio_platform_data espresso_gpio_i2c7_pdata = {
+ .udelay = 3,
+ .timeout = 0,
+ .sda_pin = GPIO_FUEL_SDA,
+ .scl_pin = GPIO_FUEL_SCL,
+};
+
+static struct platform_device espresso_gpio_i2c7_device = {
+ .name = "i2c-gpio",
+ .id = 7,
+ .dev = {
+ .platform_data = &espresso_gpio_i2c7_pdata,
+ },
+};
+
+static void smb_charger_register_callbacks(
+ struct smb_charger_callbacks *ptr)
+{
+ espresso_charger_callbacks = ptr;
+}
+
+static void set_chg_state(int cable_type)
+{
+ if (espresso_charger_callbacks && espresso_charger_callbacks->set_charging_state)
+ espresso_charger_callbacks->set_charging_state(espresso_charger_callbacks,
+ cable_type);
+
+ omap4_espresso_usb_detected(cable_type);
+ omap4_espresso_tsp_ta_detect(cable_type);
+}
+
+static struct smb_charger_data smb_pdata = {
+ .set_charge = charger_enble_set,
+ .register_callbacks = smb_charger_register_callbacks,
+};
+
+static const __initdata struct i2c_board_info smb136_i2c[] = {
+ {
+ I2C_BOARD_INFO("smb136-charger", 0x4D), /* 9A >> 1 */
+ .platform_data = &smb_pdata,
+ },
+};
+
+static const __initdata struct i2c_board_info smb347_i2c[] = {
+ {
+ I2C_BOARD_INFO("smb347-charger", 0x0C >> 1),
+ .platform_data = &smb_pdata,
+ },
+};
+
+
+static void max17042_fuelgauge_register_callbacks(
+ struct max17042_fuelgauge_callbacks *ptr)
+{
+ fuelgauge_callback = ptr;
+}
+
+static struct max17042_platform_data max17042_pdata = {
+ .register_callbacks = &max17042_fuelgauge_register_callbacks,
+ .enable_current_sense = true,
+ .sdi_capacity = 0x1F40,
+ .sdi_vfcapacity = 0x29AB,
+ .sdi_low_bat_comp_start_vol = 3550,
+ .current_range = {
+ .range1 = 0,
+ .range2 = -100,
+ .range3 = -750,
+ .range4 = -1250,
+ .range5 = 0, /* ignored */
+ .range_max = -1250,
+ .range_max_num = 4,
+ },
+ .sdi_compensation = {
+ .range1_1_slope = 0,
+ .range1_1_offset = 3456,
+ .range1_3_slope = 0,
+ .range1_3_offset = 3536,
+ .range2_1_slope = 96,
+ .range2_1_offset = 3461,
+ .range2_3_slope = 134,
+ .range2_3_offset = 3544,
+ .range3_1_slope = 97,
+ .range3_1_offset = 3451,
+ .range3_3_slope = 27,
+ .range3_3_offset = 3454,
+ .range4_1_slope = 0,
+ .range4_1_offset = 3320,
+ .range4_3_slope = 0,
+ .range4_3_offset = 3410,
+ .range5_1_slope = 0,
+ .range5_1_offset = 3318,
+ .range5_3_slope = 0,
+ .range5_3_offset = 3383,
+ },
+};
+
+static const __initdata struct i2c_board_info max17042_i2c[] = {
+ {
+ I2C_BOARD_INFO("max17042", 0x36),
+ .platform_data = &max17042_pdata,
+ },
+};
+
+static int read_fuel_value(enum fuel_property fg_prop)
+{
+ if (fuelgauge_callback && fuelgauge_callback->get_value)
+ return fuelgauge_callback->get_value(fuelgauge_callback, fg_prop);
+ return 0;
+}
+
+static int check_charger_type(void)
+{
+ int cable_type;
+ short adc;
+
+ adc = omap4_espresso_get_adc(ADC_CHECK_1);
+ cable_type = adc > CABLE_DETECT_VALUE ?
+ CABLE_TYPE_AC :
+ CABLE_TYPE_USB;
+
+ pr_info("%s: Charger type is [%s], adc = %d\n",
+ __func__,
+ cable_type == CABLE_TYPE_AC ? "AC" : "USB",
+ adc);
+
+ return cable_type;
+}
+
+static void fuel_gauge_reset_soc(void)
+{
+ if (fuelgauge_callback && fuelgauge_callback->fg_reset_soc)
+ fuelgauge_callback->fg_reset_soc(fuelgauge_callback);
+}
+
+static void fuel_gauge_adjust_capacity(void)
+{
+ if (fuelgauge_callback && fuelgauge_callback->set_adjust_capacity)
+ fuelgauge_callback->set_adjust_capacity(fuelgauge_callback);
+}
+
+static void fuel_gauge_full_comp(u32 is_recharging, u32 pre_update)
+{
+ if (fuelgauge_callback &&
+ fuelgauge_callback->full_charged_compensation)
+ fuelgauge_callback->full_charged_compensation(fuelgauge_callback,
+ is_recharging, pre_update);
+}
+
+static void fuel_gauge_vf_fullcap_range(void)
+{
+ if (fuelgauge_callback && fuelgauge_callback->check_vf_fullcap_range)
+ fuelgauge_callback->check_vf_fullcap_range(fuelgauge_callback);
+}
+
+static int fuel_gauge_lowbat_compensation(struct bat_information bat_info)
+{
+ if (fuelgauge_callback &&
+ fuelgauge_callback->check_low_batt_compensation) {
+ return fuelgauge_callback->
+ check_low_batt_compensation(fuelgauge_callback, bat_info);
+ }
+ return 0;
+}
+
+static int fuel_gauge_check_cap_corruption(void)
+{
+ if (fuelgauge_callback &&
+ fuelgauge_callback->check_cap_corruption) {
+ return fuelgauge_callback->check_cap_corruption(fuelgauge_callback);
+ }
+ return 0;
+}
+
+static void fuel_gauge_update_fullcap(void)
+{
+ if (fuelgauge_callback &&
+ fuelgauge_callback->update_remcap_to_fullcap)
+ fuelgauge_callback->update_remcap_to_fullcap(fuelgauge_callback);
+}
+
+static int fuelgauge_register_value(u8 addr)
+{
+ if (fuelgauge_callback &&
+ fuelgauge_callback->get_register_value)
+ return fuelgauge_callback->
+ get_register_value(fuelgauge_callback, addr);
+
+ return 0;
+}
+
+static void battery_manager_register_callbacks(
+ struct battery_manager_callbacks *ptr)
+{
+ batman_callback = ptr;
+}
+
+static struct batman_platform_data battery_manager_pdata = {
+ .get_fuel_value = read_fuel_value,
+ .set_charger_state = set_chg_state,
+ .set_charger_en = charger_enble_set,
+ .get_charger_type = check_charger_type,
+ .reset_fuel_soc = fuel_gauge_reset_soc,
+ .full_charger_comp = fuel_gauge_full_comp,
+ .update_fullcap_value = fuel_gauge_update_fullcap,
+ .fg_adjust_capacity = fuel_gauge_adjust_capacity,
+ .low_bat_compensation = fuel_gauge_lowbat_compensation,
+ .check_vf_fullcap_range = fuel_gauge_vf_fullcap_range,
+ .check_cap_corruption = fuel_gauge_check_cap_corruption,
+ .register_callbacks = battery_manager_register_callbacks,
+ .get_fg_register = fuelgauge_register_value,
+ .high_block_temp = HIGH_BLOCK_TEMP,
+ .high_recover_temp = HIGH_RECOVER_TEMP,
+ .low_block_temp = LOW_BLOCK_TEMP,
+ .low_recover_temp = LOW_RECOVER_TEMP,
+ .recharge_voltage = 4150000,
+ .limit_charging_time = 36000, /* 10hour */
+ .limit_recharging_time = 5400, /* 90min */
+ .ta_gpio = GPIO_TA_NCONNECTED,
+};
+
+static struct platform_device battery_manager_device = {
+ .name = "battery_manager",
+ .id = -1,
+ .dev = {
+ .platform_data = &battery_manager_pdata,
+ },
+};
+
+void check_jig_status(int status)
+{
+ if (status) {
+ pr_info("%s: JIG on, resetting fuel gauge capacity\n", __func__);
+ if (fuelgauge_callback && fuelgauge_callback->reset_capacity)
+ fuelgauge_callback->reset_capacity(fuelgauge_callback);
+ }
+
+ max17042_pdata.jig_on = status;
+ battery_manager_pdata.jig_on = status;
+}
+
+static __init int setup_boot_mode(char *str)
+{
+ unsigned int _bootmode;
+
+ if (!kstrtouint(str, 0, &_bootmode))
+ bootmode = _bootmode;
+
+ return 0;
+}
+__setup("bootmode=", setup_boot_mode);
+
+void __init omap4_espresso_charger_init(void)
+{
+ int ret;
+
+ charger_gpio_init();
+
+ battery_manager_pdata.bootmode = bootmode;
+ smb_pdata.hw_revision = system_rev;
+
+ if (!gpio_is_valid(GPIO_TA_NCONNECTED))
+ gpio_request(GPIO_TA_NCONNECTED, "TA_nCONNECTED");
+
+ ret = platform_device_register(&espresso_gpio_i2c5_device);
+ if (ret < 0)
+ pr_err("%s: gpio_i2c5 device register fail\n", __func__);
+
+ ret = platform_device_register(&espresso_gpio_i2c7_device);
+ if (ret < 0)
+ pr_err("%s: gpio_i2c7 device register fail\n", __func__);
+
+ if (board_is_espresso10()) {
+ i2c_register_board_info(5, smb347_i2c, ARRAY_SIZE(smb347_i2c));
+ max17042_pdata.sdi_capacity = 0x3730;
+ max17042_pdata.sdi_vfcapacity = 0x4996;
+ max17042_pdata.byd_capacity = 0x36B0;
+ max17042_pdata.byd_vfcapacity = 0x48EA;
+ max17042_pdata.sdi_low_bat_comp_start_vol = 3600;
+ max17042_pdata.byd_low_bat_comp_start_vol = 3650;
+ max17042_pdata.current_range.range2 = -200;
+ max17042_pdata.current_range.range3 = -600;
+ max17042_pdata.current_range.range4 = -1500;
+ max17042_pdata.current_range.range5 = -2500;
+ max17042_pdata.current_range.range_max = -2500;
+ max17042_pdata.current_range.range_max_num = 5;
+ max17042_pdata.sdi_compensation.range1_1_offset = 3438;
+ max17042_pdata.sdi_compensation.range1_3_offset = 3591;
+ max17042_pdata.sdi_compensation.range2_1_slope = 45;
+ max17042_pdata.sdi_compensation.range2_1_offset = 3447;
+ max17042_pdata.sdi_compensation.range2_3_slope = 78;
+ max17042_pdata.sdi_compensation.range2_3_offset = 3606;
+ max17042_pdata.sdi_compensation.range3_1_slope = 54;
+ max17042_pdata.sdi_compensation.range3_1_offset = 3453;
+ max17042_pdata.sdi_compensation.range3_3_slope = 92;
+ max17042_pdata.sdi_compensation.range3_3_offset = 3615;
+ max17042_pdata.sdi_compensation.range4_1_slope = 53;
+ max17042_pdata.sdi_compensation.range4_1_offset = 3451;
+ max17042_pdata.sdi_compensation.range4_3_slope = 94;
+ max17042_pdata.sdi_compensation.range4_3_offset = 3618;
+ } else {
+ i2c_register_board_info(5, smb136_i2c, ARRAY_SIZE(smb136_i2c));
+ }
+
+ i2c_register_board_info(7, max17042_i2c, ARRAY_SIZE(max17042_i2c));
+
+ ret = platform_device_register(&battery_manager_device);
+ if (ret < 0)
+ pr_err("%s: battery monitor device register fail\n", __func__);
+}
diff --git a/arch/arm/mach-omap2/board-espresso-sdio.c b/arch/arm/mach-omap2/board-espresso-sdio.c
new file mode 100644
index 0000000..48b522b
--- /dev/null
+++ b/arch/arm/mach-omap2/board-espresso-sdio.c
@@ -0,0 +1,102 @@
+/* arch/arm/mach-omap2/board-espresso-sdio.c
+ *
+ * Copyright (C) 2011 Samsung Electronics Co, Ltd.
+ *
+ * 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/i2c/twl.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+
+#include <plat/irqs.h>
+#include <plat/mmc.h>
+
+#include "hsmmc.h"
+#include "board-espresso.h"
+
+static struct omap2_hsmmc_info espresso_mmc_info[] = {
+ {
+ .mmc = 2,
+ .nonremovable = true,
+ .caps = MMC_CAP_8_BIT_DATA
+ | MMC_CAP_1_8V_DDR | MMC_CAP_UHS_DDR50,
+ .ocr_mask = MMC_VDD_165_195,
+ .gpio_wp = -EINVAL,
+ .gpio_cd = -EINVAL,
+ },
+ {
+ .mmc = 1,
+ .caps = MMC_CAP_8_BIT_DATA,
+ .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 = &espresso_wifi_data,
+ },
+ {} /* Terminator */
+};
+
+static int espresso_hsmmc_late_init(struct device *dev)
+{
+ int ret = 0;
+ struct platform_device *pdev =
+ container_of(dev, struct platform_device, dev);
+ struct omap_mmc_platform_data *pdata = dev->platform_data;
+
+ /* Setting MMC1 Card detect IRQ */
+ if (pdev->id == 0) {
+ ret = twl6030_mmc_card_detect_config();
+ if (ret)
+ pr_err("%s: failed configuring MMC1 card detect\n", __func__);
+ pdata->slots[0].card_detect_irq =
+ TWL6030_IRQ_BASE + MMCDETECT_INTR_OFFSET;
+ pdata->slots[0].card_detect = twl6030_mmc_card_detect;
+ }
+
+ return ret;
+}
+
+static void __init espresso_hsmmc_set_late_init(struct device *dev)
+{
+ struct omap_mmc_platform_data *pdata;
+
+ /* dev can be null if CONFIG_MMC_OMAP_HS is not set */
+ if (!dev) {
+ pr_err("%s: failed!\n", __func__);
+ return;
+ }
+
+ pdata = dev->platform_data;
+ pdata->init = espresso_hsmmc_late_init;
+}
+
+static void __init espresso_hsmmc_init(struct omap2_hsmmc_info *controllers)
+{
+ struct omap2_hsmmc_info *c;
+
+ omap2_hsmmc_init(controllers);
+ for (c = controllers; c->mmc; c++)
+ espresso_hsmmc_set_late_init(c->dev);
+}
+
+void __init omap4_espresso_sdio_init(void)
+{
+ espresso_hsmmc_init(espresso_mmc_info);
+}
diff --git a/arch/arm/mach-omap2/board-espresso-sensors.c b/arch/arm/mach-omap2/board-espresso-sensors.c
new file mode 100644
index 0000000..9d90afa
--- /dev/null
+++ b/arch/arm/mach-omap2/board-espresso-sensors.c
@@ -0,0 +1,230 @@
+/* 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/i2c.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include "mux.h"
+
+#include <linux/gp2a.h>
+#include <linux/i2c/twl6030-gpadc.h>
+#include <linux/regulator/consumer.h>
+#include <linux/bh1721fvc.h>
+#include <linux/yas.h>
+#include <linux/al3201.h>
+
+#include "board-espresso.h"
+
+#define GPIO_ALS_INT 33
+#define GPIO_PS_VOUT 1
+#define GPIO_MSENSE_IRQ 157
+
+#define GP2A_LIGHT_ADC_CHANNEL 4
+
+#define YAS_TA_OFFSET_ESPRESSO {0, 0, 0}
+#define YAS_USB_OFFSET_ESPRESSO {0, 0, 0}
+#define YAS_TA_OFFSET_ESPRESSO10 {200, -4600, -1100}
+#define YAS_USB_OFFSET_ESPRESSO10 {0, -1100, -300}
+#define YAS_FULL_OFFSET {0, 0, 0}
+
+static int bh1721fvc_light_sensor_reset(void)
+{
+ pr_debug("%s\n", __func__);
+
+ omap_mux_init_gpio(GPIO_ALS_INT, OMAP_PIN_OUTPUT);
+
+ gpio_free(GPIO_ALS_INT);
+
+ gpio_request(GPIO_ALS_INT, "LIGHT_SENSOR_RESET");
+
+ gpio_direction_output(GPIO_ALS_INT, 0);
+
+ udelay(2);
+
+ gpio_direction_output(GPIO_ALS_INT, 1);
+
+ return 0;
+}
+
+static struct bh1721fvc_platform_data bh1721fvc_pdata = {
+ .reset = bh1721fvc_light_sensor_reset,
+};
+
+static int gp2a_light_adc_value(void)
+{
+ if (system_rev >= 6)
+ return twl6030_get_gpadc_conversion(GP2A_LIGHT_ADC_CHANNEL) / 4;
+ else
+ return twl6030_get_gpadc_conversion(GP2A_LIGHT_ADC_CHANNEL);
+}
+
+static void omap4_espresso_sensors_regulator_on(bool on)
+{
+ struct regulator *reg_v28;
+ struct regulator *reg_v18;
+
+ reg_v28 = regulator_get(NULL, "VAP_IO_2.8V");
+ if (IS_ERR(reg_v28)) {
+ pr_err("%s [%d] failed to get v2.8 regulator\n",
+ __func__, __LINE__);
+ return;
+ }
+ reg_v18 = regulator_get(NULL, "VDD_IO_1.8V");
+ if (IS_ERR(reg_v18)) {
+ pr_err("%s [%d] failed to get v1.8 regulator\n",
+ __func__, __LINE__);
+ return;
+ }
+
+ pr_debug("%s: %d\n", __func__, on);
+
+ if (on) {
+ regulator_enable(reg_v28);
+ regulator_enable(reg_v18);
+ } else {
+ regulator_disable(reg_v18);
+ regulator_disable(reg_v28);
+ }
+ regulator_put(reg_v28);
+ regulator_put(reg_v18);
+ if (!board_is_espresso10())
+ msleep(20);
+}
+
+static struct gp2a_platform_data gp2a_pdata = {
+ .p_out = GPIO_PS_VOUT,
+ .light_adc_value = gp2a_light_adc_value,
+ .ldo_on = omap4_espresso_sensors_regulator_on,
+};
+
+struct mag_platform_data magnetic_pdata = {
+ .power_on = omap4_espresso_sensors_regulator_on,
+ .offset_enable = 0,
+ .orientation = 8, /* P31xx default */
+ .chg_status = CABLE_TYPE_NONE,
+ .ta_offset.v = YAS_TA_OFFSET_ESPRESSO,
+ .usb_offset.v = YAS_USB_OFFSET_ESPRESSO,
+ .full_offset.v = YAS_FULL_OFFSET,
+};
+
+void omap4_espresso_set_chager_type(int type)
+{
+ static int prev = CABLE_TYPE_NONE;
+ magnetic_pdata.chg_status = type;
+
+ if (board_is_espresso10()) {
+ if (prev != type)
+ magnetic_pdata.offset_enable = 1;
+ prev = type;
+ }
+}
+
+struct acc_platform_data accelerometer_pdata = {
+ .cal_path = "/efs/calibration_data",
+ .ldo_on = omap4_espresso_sensors_regulator_on,
+ .orientation = 8, /* P31xx default */
+};
+
+static struct al3201_platform_data al3201_pdata = {
+ .power_on = omap4_espresso_sensors_regulator_on,
+};
+
+static struct i2c_board_info __initdata espresso10_sensors_i2c4_boardinfo[] = {
+ {
+ I2C_BOARD_INFO("bh1721fvc", 0x23),
+ .platform_data = &bh1721fvc_pdata,
+ },
+};
+
+static struct i2c_board_info __initdata espresso_sensors_i2c4_boardinfo_rf[] = {
+ {
+ I2C_BOARD_INFO("gp2a", 0x44),
+ .platform_data = &gp2a_pdata,
+ },
+};
+
+static struct i2c_board_info __initdata espresso_sensors_i2c4_boardinfo_wf[] = {
+ {
+ I2C_BOARD_INFO("AL3201", 0x1c),
+ .platform_data = &al3201_pdata,
+ },
+};
+
+static struct i2c_board_info __initdata espresso_common_sensors_i2c4_boardinfo[] = {
+ {
+ I2C_BOARD_INFO("accelerometer", 0x18),
+ .platform_data = &accelerometer_pdata,
+ },
+ {
+ I2C_BOARD_INFO("geomagnetic", 0x2e),
+ .platform_data = &magnetic_pdata,
+ },
+};
+
+void __init omap4_espresso_sensors_init(void)
+{
+ int32_t ta_offset_espresso10[] = YAS_TA_OFFSET_ESPRESSO10;
+ int32_t usb_offset_espresso10[] = YAS_USB_OFFSET_ESPRESSO10;
+ struct gpio sensors_gpios[] = {
+ {
+ .flags = GPIOF_IN,
+ .gpio = GPIO_ALS_INT,
+ .label = "ALS_INT_18",
+ },
+ {
+ .flags = GPIOF_IN,
+ .gpio = GPIO_PS_VOUT,
+ .label = "PS_VOUT",
+ },
+ {
+ .flags = GPIOF_IN,
+ .gpio = GPIO_MSENSE_IRQ,
+ .label = "MSENSE_IRQ",
+ },
+ };
+ gpio_request_array(sensors_gpios, ARRAY_SIZE(sensors_gpios));
+
+ omap_mux_init_gpio(GPIO_MSENSE_IRQ,
+ OMAP_PIN_OUTPUT);
+
+ gpio_free(GPIO_MSENSE_IRQ);
+
+ gpio_request(GPIO_MSENSE_IRQ, "MSENSE_IRQ");
+
+ gpio_direction_output(GPIO_MSENSE_IRQ, 1);
+
+ if (!board_is_espresso10()) {
+ if (board_has_modem()) {
+ i2c_register_board_info(4, espresso_sensors_i2c4_boardinfo_rf,
+ ARRAY_SIZE(espresso_sensors_i2c4_boardinfo_rf));
+ } else {
+ i2c_register_board_info(4, espresso_sensors_i2c4_boardinfo_wf,
+ ARRAY_SIZE(espresso_sensors_i2c4_boardinfo_wf));
+ }
+ } else {
+ magnetic_pdata.orientation = 7;
+ accelerometer_pdata.orientation = 6;
+ magnetic_pdata.ta_offset.v[0] = ta_offset_espresso10[0];
+ magnetic_pdata.ta_offset.v[1] = ta_offset_espresso10[1];
+ magnetic_pdata.ta_offset.v[2] = ta_offset_espresso10[2];
+ magnetic_pdata.usb_offset.v[0] = usb_offset_espresso10[0];
+ magnetic_pdata.usb_offset.v[1] = usb_offset_espresso10[1];
+ magnetic_pdata.usb_offset.v[2] = usb_offset_espresso10[2];
+ i2c_register_board_info(4, espresso10_sensors_i2c4_boardinfo,
+ ARRAY_SIZE(espresso10_sensors_i2c4_boardinfo));
+ }
+
+ i2c_register_board_info(4, espresso_common_sensors_i2c4_boardinfo,
+ ARRAY_SIZE(espresso_common_sensors_i2c4_boardinfo));
+}
diff --git a/arch/arm/mach-omap2/board-espresso-serial.c b/arch/arm/mach-omap2/board-espresso-serial.c
new file mode 100644
index 0000000..a8c0548
--- /dev/null
+++ b/arch/arm/mach-omap2/board-espresso-serial.c
@@ -0,0 +1,292 @@
+/* arch/arm/mach-omap2/board-espresso-serial.c
+ *
+ * Copyright (C) 2011 Samsung Electronics Co, Ltd.
+ *
+ * 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/i2c.h>
+#include <linux/i2c-gpio.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/proc_fs.h>
+#include <linux/uaccess.h>
+#include <linux/hwspinlock.h>
+#include <plat/common.h>
+#include <plat/omap_hwmod.h>
+#include <plat/omap-serial.h>
+
+#include "board-espresso.h"
+#include "mux.h"
+
+#define GPIO_GPS_PWR_EN 173
+#define GPIO_GPS_NRST 178
+
+#define GPIO_ADC_I2C_SDA 66
+#define GPIO_ADC_I2C_SCL 65
+#define GPIO_ADC_I2C_SDA_BBY 137
+#define GPIO_ADC_I2C_SCL_BBY 134
+
+#define GPIO_MHL_SDA 98
+#define GPIO_MHL_SCL 99
+
+static struct i2c_board_info __initdata espresso_i2c_board_info[] = {
+ {
+ I2C_BOARD_INFO("ducati", 0x20),
+ .irq = OMAP44XX_IRQ_I2C2,
+ .ext_master = true,
+ },
+};
+
+static void __init omap_i2c_hwspinlock_init(int bus_id, int spinlock_id,
+ struct omap_i2c_bus_board_data *pdata)
+{
+ /* spinlock_id should be -1 for a generic lock request */
+ if (spinlock_id < 0)
+ pdata->handle = hwspin_lock_request();
+ else
+ pdata->handle = hwspin_lock_request_specific(spinlock_id);
+
+ if (pdata->handle != NULL) {
+ pdata->hwspin_lock_timeout = hwspin_lock_timeout;
+ pdata->hwspin_unlock = hwspin_unlock;
+ } else {
+ pr_err("I2C hwspinlock request failed for bus %d\n", bus_id);
+ }
+}
+
+static struct omap_i2c_bus_board_data __initdata espresso_i2c_1_bus_pdata;
+static struct omap_i2c_bus_board_data __initdata espresso_i2c_2_bus_pdata;
+static struct omap_i2c_bus_board_data __initdata espresso_i2c_3_bus_pdata;
+static struct omap_i2c_bus_board_data __initdata espresso_i2c_4_bus_pdata;
+
+static void __init espresso_i2c_init(void)
+{
+ omap_i2c_hwspinlock_init(1, 0, &espresso_i2c_1_bus_pdata);
+ omap_i2c_hwspinlock_init(2, 1, &espresso_i2c_2_bus_pdata);
+ omap_i2c_hwspinlock_init(3, 2, &espresso_i2c_3_bus_pdata);
+ omap_i2c_hwspinlock_init(4, 3, &espresso_i2c_4_bus_pdata);
+
+ omap_register_i2c_bus_board_data(1, &espresso_i2c_1_bus_pdata);
+ omap_register_i2c_bus_board_data(2, &espresso_i2c_2_bus_pdata);
+ omap_register_i2c_bus_board_data(3, &espresso_i2c_3_bus_pdata);
+ omap_register_i2c_bus_board_data(4, &espresso_i2c_4_bus_pdata);
+
+ /*
+ * Phoenix Audio IC needs I2C1 to
+ * start with 400 KHz or less
+ */
+ omap_register_i2c_bus(1, 400, NULL, 0);
+ omap_register_i2c_bus(2, 400, espresso_i2c_board_info,
+ ARRAY_SIZE(espresso_i2c_board_info));
+ omap_register_i2c_bus(3, 400, NULL, 0);
+ omap_register_i2c_bus(4, 400, NULL, 0);
+}
+
+static struct i2c_gpio_platform_data espresso_gpio_i2c6_pdata = {
+ .sda_pin = GPIO_ADC_I2C_SDA,
+ .scl_pin = GPIO_ADC_I2C_SCL,
+ .udelay = 10,
+ .timeout = 0,
+};
+
+static struct platform_device espresso_gpio_i2c6_device = {
+ .name = "i2c-gpio",
+ .id = 6,
+ .dev = {
+ .platform_data = &espresso_gpio_i2c6_pdata,
+ }
+};
+
+static struct i2c_gpio_platform_data espresso_gpio_i2c8_pdata = {
+ .sda_pin = GPIO_MHL_SDA,
+ .scl_pin = GPIO_MHL_SCL,
+ .udelay = 3,
+ .timeout = 0,
+};
+
+static struct platform_device espresso_gpio_i2c8_device = {
+ .name = "i2c-gpio",
+ .id = 8,
+ .dev = {
+ .platform_data = &espresso_gpio_i2c8_pdata,
+ },
+};
+
+static void __init espresso_gpio_i2c_init(void)
+{
+ if (board_is_espresso10() && board_is_bestbuy_variant()) {
+ espresso_gpio_i2c6_pdata.sda_pin = GPIO_ADC_I2C_SDA_BBY;
+ espresso_gpio_i2c6_pdata.sda_pin = GPIO_ADC_I2C_SCL_BBY;
+ }
+}
+
+static void espresso_bcmgps_init(void)
+{
+ struct device *gps_dev;
+ struct gpio gps_gpios[] = {
+ {
+ .flags = GPIOF_OUT_INIT_LOW,
+ .gpio = GPIO_GPS_PWR_EN,
+ .label = "GPS_PWR_EN",
+ },
+ {
+ .flags = GPIOF_OUT_INIT_HIGH,
+ .gpio = GPIO_GPS_NRST,
+ .label = "GPS_nRST",
+ },
+ };
+
+ gps_dev = device_create(sec_class, NULL, 0, NULL, "gps");
+ if (IS_ERR(gps_dev)) {
+ pr_err("(%s): failed to created device (gps)!\n", __func__);
+ return;
+ }
+
+ gpio_request_array(gps_gpios, ARRAY_SIZE(gps_gpios));
+
+ gpio_export(GPIO_GPS_PWR_EN, 1);
+ gpio_export(GPIO_GPS_NRST, 1);
+
+ gpio_export_link(gps_dev, gps_gpios[0].label, GPIO_GPS_PWR_EN);
+ gpio_export_link(gps_dev, gps_gpios[1].label, GPIO_GPS_NRST);
+}
+
+static struct omap_device_pad espresso_uart1_pads[] __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 espresso_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 espresso_uart3_pads[] __initdata = {
+ {
+ .name = "uart3_tx_irtx.uart3_tx_irtx",
+ .enable = OMAP_PIN_OUTPUT | OMAP_MUX_MODE0,
+ },
+ {
+ .name = "uart3_rx_irrx.uart3_rx_irrx",
+ .enable = OMAP_PIN_INPUT | OMAP_MUX_MODE0,
+ },
+};
+
+static struct omap_device_pad espresso_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 espresso_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 = 0,
+ .wake_peer = bcm_bt_lpm_exit_lpm_locked,
+ .rts_mux_driver_control = 1,
+};
+
+static void __init omap_serial_none_pads_cfg_mux(void)
+{
+ struct omap_mux_partition *core = omap_mux_get("core");
+
+ omap_mux_write(core,
+ OMAP_MUX_MODE7 | OMAP_PIN_INPUT_PULLDOWN,
+ OMAP4_CTRL_MODULE_PAD_UART3_RX_IRRX_OFFSET);
+ omap_mux_write(core,
+ OMAP_MUX_MODE7 | OMAP_PIN_INPUT_PULLDOWN,
+ OMAP4_CTRL_MODULE_PAD_UART3_TX_IRTX_OFFSET);
+}
+
+static void __init espresso_uart_init(void)
+{
+ omap_serial_init_port_pads(0, espresso_uart1_pads,
+ ARRAY_SIZE(espresso_uart1_pads), NULL);
+ omap_serial_init_port_pads(1, espresso_uart2_pads,
+ ARRAY_SIZE(espresso_uart2_pads),
+ &espresso_uart2_info);
+ omap_serial_init_port_pads(2, espresso_uart3_pads,
+ ARRAY_SIZE(espresso_uart3_pads), NULL);
+ omap_serial_init_port_pads(3, espresso_uart4_pads,
+ ARRAY_SIZE(espresso_uart4_pads), NULL);
+
+ espresso_bcmgps_init();
+}
+
+static struct platform_device *espresso_serial_devices[] __initdata = {
+ &espresso_gpio_i2c6_device,
+};
+
+static struct platform_device *espresso10_serial_devices[] __initdata = {
+ &espresso_gpio_i2c8_device,
+};
+
+void __init omap4_espresso_serial_init(void)
+{
+ espresso_i2c_init();
+ espresso_gpio_i2c_init();
+ espresso_uart_init();
+
+ platform_add_devices(espresso_serial_devices,
+ ARRAY_SIZE(espresso_serial_devices));
+ if (board_is_espresso10() && board_is_bestbuy_variant()) {
+ platform_add_devices(espresso10_serial_devices,
+ ARRAY_SIZE(espresso10_serial_devices));
+ }
+}
+
+int __init omap4_espresso_serial_late_init(void)
+{
+ if (system_rev > 6 && board_has_modem())
+ omap_serial_none_pads_cfg_mux();
+
+ return 0;
+}
+late_initcall(omap4_espresso_serial_late_init);
diff --git a/arch/arm/mach-omap2/board-espresso-vibrator.c b/arch/arm/mach-omap2/board-espresso-vibrator.c
new file mode 100644
index 0000000..6429a82
--- /dev/null
+++ b/arch/arm/mach-omap2/board-espresso-vibrator.c
@@ -0,0 +1,154 @@
+/* arch/arm/mach-omap2/board-espresso-vibrator.c
+ *
+ * Copyright (C) 2012 Samsung Electronics Co. Ltd. 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/hrtimer.h>
+#include <linux/gpio.h>
+#include <linux/wakelock.h>
+#include <linux/mutex.h>
+#include <asm/mach-types.h>
+
+#include <../../../drivers/staging/android/timed_output.h>
+
+#include "mux.h"
+#include "board-espresso.h"
+
+#define GPIO_MOTOR_EN 38
+
+#define MAX_TIMEOUT 10000 /* 10sec */
+
+static struct vibrator {
+ struct wake_lock wklock;
+ struct hrtimer timer;
+ struct mutex lock;
+ bool enabled;
+} vibdata;
+
+static void vibrator_off(void)
+{
+ if (!vibdata.enabled)
+ return;
+ gpio_set_value(GPIO_MOTOR_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(GPIO_MOTOR_EN, 1);
+
+ 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 void __init omap_vibrator_none_pads_cfg_mux(void)
+{
+ omap_mux_write(omap_mux_get("core"),
+ OMAP_MUX_MODE7 | OMAP_PIN_INPUT_PULLDOWN,
+ OMAP4_CTRL_MODULE_PAD_GPMC_AD14_OFFSET);
+}
+
+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;
+
+ 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);
+
+ return -1;
+}
+
+int __init omap4_espresso_vibrator_init(void)
+{
+ int ret;
+
+ if (!board_has_modem()) {
+ omap_vibrator_none_pads_cfg_mux();
+ return 0;
+ }
+
+ gpio_request_one(GPIO_MOTOR_EN, GPIOF_OUT_INIT_LOW, "MOTOR_EN");
+
+ ret = vibrator_init();
+ if (ret < 0) {
+ pr_err("vib: vibrator_init fail.");
+ gpio_free(GPIO_MOTOR_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_espresso_vibrator_init);
diff --git a/arch/arm/mach-omap2/board-espresso-wifi.c b/arch/arm/mach-omap2/board-espresso-wifi.c
new file mode 100644
index 0000000..8faad70
--- /dev/null
+++ b/arch/arm/mach-omap2/board-espresso-wifi.c
@@ -0,0 +1,387 @@
+/* arch/arm/mach-omap2/board-espresso-wifi.c
+ *
+ * Copyright (C) 2011 Samsung Electronics Co, Ltd.
+ *
+ * Based on mach-omap2/board-tuna-wifi.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/delay.h>
+#include <linux/err.h>
+#include <asm/mach-types.h>
+#include <linux/gpio.h>
+#include <linux/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 "board-espresso.h"
+#include "hsmmc.h"
+
+#define GPIO_WLAN_HOST_WAKE 81
+#define GPIO_WLAN_EN 104
+
+#ifdef CONFIG_DHD_USE_STATIC_BUF
+#define WLAN_STATIC_SCAN_BUF0 5
+#define WLAN_STATIC_SCAN_BUF1 6
+#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 DHD_SKB_HDRSIZE 336
+#define DHD_SKB_1PAGE_BUFSIZE ((PAGE_SIZE*1)-DHD_SKB_HDRSIZE)
+#define DHD_SKB_2PAGE_BUFSIZE ((PAGE_SIZE*2)-DHD_SKB_HDRSIZE)
+#define DHD_SKB_4PAGE_BUFSIZE ((PAGE_SIZE*4)-DHD_SKB_HDRSIZE)
+
+#define WLAN_SKB_BUF_NUM 16
+
+static struct sk_buff *wlan_static_skb[WLAN_SKB_BUF_NUM];
+
+struct wifi_mem_prealloc {
+ 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 *espresso_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;
+}
+#endif
+
+int __init espresso_init_wifi_mem(void)
+{
+#ifdef CONFIG_DHD_USE_STATIC_BUF
+ 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;
+ }
+#endif
+ return 0;
+}
+
+#define WLC_CNTRY_BUF_SZ 4
+
+/* wifi private data */
+static int espresso_wifi_cd; /* WIFI virtual 'card detect' status */
+static void (*wifi_status_cb)(int card_present, void *dev_id);
+static void *wifi_status_cb_devid;
+
+static unsigned char espresso_mac_addr[IFHWADDRLEN]
+ = { 0, 0x90, 0x4c, 0, 0, 0 };
+
+static struct resource espresso_wifi_resources[] = {
+ [0] = {
+ .name = "bcmdhd_wlan_irq",
+ .flags = IORESOURCE_IRQ
+ | IORESOURCE_IRQ_HIGHLEVEL
+ | IORESOURCE_IRQ_SHAREABLE,
+ },
+};
+
+static int espresso_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 espresso_wifi_status(struct device *dev)
+{
+ return espresso_wifi_cd;
+}
+
+struct mmc_platform_data espresso_wifi_data = {
+ .ocr_mask = MMC_VDD_165_195 | MMC_VDD_20_21,
+ .built_in = 1,
+ .status = espresso_wifi_status,
+ .card_present = 0,
+ .register_status_notify = espresso_wifi_status_register,
+};
+
+static int espresso_wifi_set_carddetect(int val)
+{
+ pr_debug("%s: %d\n", __func__, val);
+ espresso_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;
+}
+
+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 espresso_vmmc5_supply = {
+ .supply = "vmmc",
+ .dev_name = "omap_hsmmc.4",
+};
+
+static struct regulator_init_data espresso_vmmc5 = {
+ .constraints = {
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ .num_consumer_supplies = 1,
+ .consumer_supplies = &espresso_vmmc5_supply,
+};
+
+static struct fixed_voltage_config espresso_vwlan = {
+ .supply_name = "vwl1271",
+ .microvolts = 2000000, /* 2.0V */
+ .startup_delay = 70000, /* 70msec */
+ .gpio = GPIO_WLAN_EN,
+ .enable_high = 1,
+ .enabled_at_boot = 0,
+ .init_data = &espresso_vmmc5,
+};
+
+static struct platform_device omap_vwlan_device = {
+ .name = "reg-fixed-voltage",
+ .id = 1,
+ .dev = {
+ .platform_data = &espresso_vwlan,
+ },
+};
+
+static int espresso_wifi_power(int on)
+{
+ pr_debug("%s: %d\n", __func__, on);
+ gpio_set_value(espresso_vwlan.gpio, on);
+ msleep(300);
+ return 0;
+}
+
+static int espresso_wifi_reset(int on)
+{
+ pr_debug("%s: do nothing\n", __func__);
+ return 0;
+}
+
+static int __init espresso_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;
+ espresso_mac_addr[i++] = (u8)val;
+ }
+
+ return 1;
+}
+__setup("androidboot.macaddr=", espresso_mac_addr_setup);
+
+static int espresso_wifi_get_mac_addr(unsigned char *buf)
+{
+ uint rand_mac;
+
+ if (!buf)
+ return -EFAULT;
+
+ if ((espresso_mac_addr[4] == 0) && (espresso_mac_addr[5] == 0)) {
+ srandom32((uint)jiffies);
+ rand_mac = random32();
+ espresso_mac_addr[3] = (unsigned char)rand_mac;
+ espresso_mac_addr[4] = (unsigned char)(rand_mac >> 8);
+ espresso_mac_addr[5] = (unsigned char)(rand_mac >> 16);
+ }
+ memcpy(buf, espresso_mac_addr, IFHWADDRLEN);
+
+ return 0;
+}
+
+/* Customized Locale table : OPTIONAL feature */
+struct cntry_locales_custom {
+ char iso_abbrev[WLC_CNTRY_BUF_SZ];
+ char custom_locale[WLC_CNTRY_BUF_SZ];
+ int custom_locale_rev;
+};
+
+static struct cntry_locales_custom espresso_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 *espresso_wifi_get_country_code(char *ccode)
+{
+ int size = ARRAY_SIZE(espresso_wifi_translate_custom_table);
+ int i;
+
+ if (!ccode)
+ return NULL;
+
+ for (i = 0; i < size; i++)
+ if (strcmp(ccode,
+ espresso_wifi_translate_custom_table[i].iso_abbrev)
+ == 0)
+ return &espresso_wifi_translate_custom_table[i];
+
+ return &espresso_wifi_translate_custom_table[0];
+}
+
+static struct wifi_platform_data espresso_wifi_control = {
+ .set_power = espresso_wifi_power,
+ .set_reset = espresso_wifi_reset,
+ .set_carddetect = espresso_wifi_set_carddetect,
+#ifdef CONFIG_DHD_USE_STATIC_BUF
+ .mem_prealloc = espresso_wifi_mem_prealloc,
+#else
+ .mem_prealloc = NULL,
+#endif
+ .get_mac_addr = espresso_wifi_get_mac_addr,
+ .get_country_code = espresso_wifi_get_country_code,
+};
+
+static struct platform_device espresso_wifi_device = {
+ .name = "bcmdhd_wlan",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(espresso_wifi_resources),
+ .resource = espresso_wifi_resources,
+ .dev = {
+ .platform_data = &espresso_wifi_control,
+ },
+};
+
+static void __init espresso_wlan_gpio(void)
+{
+ pr_debug("%s\n", __func__);
+
+ espresso_wifi_resources[0].start =
+ gpio_to_irq(GPIO_WLAN_HOST_WAKE);
+ espresso_wifi_resources[0].end =
+ espresso_wifi_resources[0].start;
+ gpio_request(GPIO_WLAN_HOST_WAKE, "WLAN_HOST_WAKE");
+ gpio_direction_input(GPIO_WLAN_HOST_WAKE);
+}
+
+void __init omap4_espresso_wifi_init(void)
+{
+ pr_debug("%s\n", __func__);
+ espresso_wlan_gpio();
+ espresso_init_wifi_mem();
+ platform_device_register(&omap_vwlan_device);
+
+ platform_device_register(&espresso_wifi_device);
+}
diff --git a/arch/arm/mach-omap2/board-espresso.c b/arch/arm/mach-omap2/board-espresso.c
new file mode 100644
index 0000000..10a505f
--- /dev/null
+++ b/arch/arm/mach-omap2/board-espresso.c
@@ -0,0 +1,482 @@
+/* arch/arm/mach-omap2/board-espresso.c
+ *
+ * Copyright (C) 2011 Samsung Electronics Co, Ltd.
+ *
+ * Based on mach-omap2/board-espresso.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/input.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/ion.h>
+#include <linux/memblock.h>
+#include <linux/omap_ion.h>
+#include <linux/reboot.h>
+#include <linux/sysfs.h>
+
+#include <plat/board.h>
+#include <plat/common.h>
+#include <plat/cpu.h>
+#include <plat/remoteproc.h>
+#include <plat/usb.h>
+
+#ifdef CONFIG_OMAP_HSI_DEVICE
+#include <plat/omap_hsi.h>
+#endif
+
+#include <mach/dmm.h>
+#include <mach/omap4-common.h>
+#include <mach/id.h>
+#ifdef CONFIG_ION_OMAP
+#include <mach/omap4_ion.h>
+#endif
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+#include "board-espresso.h"
+#include "control.h"
+#include "mux.h"
+#include "omap_ram_console.h"
+#include "omap4-sar-layout.h"
+
+#include "sec_muxtbl.h"
+
+/* gpio to distinguish WiFi and USA-BBY (P51xx)
+ *
+ * HW_REV4 | HIGH | LOW
+ * --------+------+------
+ * |IrDA O|IrDA X
+ */
+#define GPIO_HW_REV4 41
+
+#define GPIO_TA_NCONNECTED 32
+
+#define ESPRESSO_MEM_BANK_0_SIZE 0x20000000
+#define ESPRESSO_MEM_BANK_0_ADDR 0x80000000
+#define ESPRESSO_MEM_BANK_1_SIZE 0x20000000
+#define ESPRESSO_MEM_BANK_1_ADDR 0xA0000000
+
+#define OMAP_SW_BOOT_CFG_ADDR 0x4A326FF8
+#define REBOOT_FLAG_NORMAL (1 << 0)
+#define REBOOT_FLAG_RECOVERY (1 << 1)
+#define REBOOT_FLAG_POWER_OFF (1 << 4)
+#define REBOOT_FLAG_DOWNLOAD (1 << 5)
+
+#define ESPRESSO_RAM_CONSOLE_START (PLAT_PHYS_OFFSET + SZ_512M)
+
+#define ESPRESSO_ATTR_RO(_type, _name, _show) \
+ struct kobj_attribute espresso_##_type##_prop_attr_##_name = \
+ __ATTR(_name, S_IRUGO, _show, NULL)
+
+struct class *sec_class;
+EXPORT_SYMBOL(sec_class);
+
+static struct platform_device bcm4330_bluetooth_device = {
+ .name = "bcm4330_bluetooth",
+ .id = -1,
+};
+
+static struct platform_device *espresso_devices[] __initdata = {
+ &bcm4330_bluetooth_device,
+};
+
+static void __init espresso_init_early(void)
+{
+ omap2_init_common_infrastructure();
+ omap2_init_common_devices(NULL, NULL);
+
+ omap4_espresso_display_early_init();
+}
+
+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 = 500,
+};
+
+/* Board identification */
+
+static bool _board_has_modem = true;
+static bool _board_is_espresso10 = true;
+static bool _board_is_bestbuy_variant = false;
+
+/*
+ * Sets the board type
+ */
+static __init int setup_board_type(char *str)
+{
+ int lcd_id;
+
+ /* We reset the console loglevel here back to verbose, as our
+ * bootloaders pass loglevel=0 to the kernel cmdline.
+ * This is the most convinient place to do so, as this method
+ * gets executed right after parsing the loglevel param.
+ */
+ console_loglevel = 15;
+
+ if (kstrtoint(str, 0, &lcd_id)) {
+ pr_err("************************************************\n");
+ pr_err("Cannot parse lcd_panel_id command line parameter\n");
+ pr_err("Failed to detect board type, assuming espresso10\n");
+ pr_err("************************************************\n");
+ return 1;
+ }
+
+ /*
+ * P51xx bootloaders pass lcd_id=1 and on some older lcd_id=0,
+ * everything else is P31xx.
+ */
+ if (lcd_id > 1)
+ _board_is_espresso10 = false;
+
+ return 0;
+}
+early_param("lcd_panel_id", setup_board_type);
+
+/*
+ * Sets whether the device is a wifi-only variant
+ */
+static int __init espresso_set_subtype(char *str)
+{
+ #define CARRIER_WIFI_ONLY "wifi-only"
+
+ if (!strncmp(str, CARRIER_WIFI_ONLY, strlen(CARRIER_WIFI_ONLY)))
+ _board_has_modem = false;
+
+ return 0;
+}
+__setup("androidboot.carrier=", espresso_set_subtype);
+
+/*
+ * Sets whether the device is a Best Buy wifi-only variant
+ */
+static int __init espresso_set_vendor_type(char *str)
+{
+ unsigned int vendor;
+
+ if (kstrtouint(str, 0, &vendor))
+ return 0;
+
+ if (vendor == 0)
+ _board_is_bestbuy_variant = true;
+
+ return 0;
+}
+__setup("sec_vendor=", espresso_set_vendor_type);
+
+bool board_is_espresso10(void) {
+ return _board_is_espresso10;
+}
+
+bool board_has_modem(void) {
+ return _board_has_modem;
+}
+
+bool board_is_bestbuy_variant(void) {
+ return _board_is_bestbuy_variant;
+}
+
+/* Board identification end */
+
+static void espresso_power_off_charger(void)
+{
+ pr_err("Rebooting into bootloader for charger.\n");
+ arm_pm_restart('t', NULL);
+}
+
+static int espresso_reboot_call(struct notifier_block *this,
+ unsigned long code, void *cmd)
+{
+ u32 flag = REBOOT_FLAG_NORMAL;
+ char *blcmd = "RESET";
+
+ if (code == SYS_POWER_OFF) {
+ flag = REBOOT_FLAG_POWER_OFF;
+ blcmd = "POFF";
+ if (!gpio_get_value(GPIO_TA_NCONNECTED))
+ pm_power_off = espresso_power_off_charger;
+ } else if (code == SYS_RESTART) {
+ if (cmd) {
+ if (!strcmp(cmd, "recovery"))
+ flag = REBOOT_FLAG_RECOVERY;
+ else if (!strcmp(cmd, "download"))
+ flag = REBOOT_FLAG_DOWNLOAD;
+ }
+ }
+
+ omap_writel(flag, OMAP_SW_BOOT_CFG_ADDR);
+ omap_writel(*(u32 *) blcmd, OMAP_SW_BOOT_CFG_ADDR - 0x04);
+
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block espresso_reboot_notifier = {
+ .notifier_call = espresso_reboot_call,
+};
+
+static void __init espresso10_update_board_type(void)
+{
+ /* because omap4_mux_init is not called when this function is
+ * called, padconf reg must be configured by low-level function. */
+ omap_writew(OMAP_MUX_MODE3 | OMAP_PIN_INPUT,
+ OMAP4_CTRL_MODULE_PAD_CORE_MUX_PBASE +
+ OMAP4_CTRL_MODULE_PAD_GPMC_A17_OFFSET);
+
+ gpio_request(GPIO_HW_REV4, "HW_REV4");
+ if (gpio_get_value(GPIO_HW_REV4))
+ _board_is_bestbuy_variant = true;
+}
+
+static ssize_t espresso_soc_family_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ return sprintf(buf, "OMAP%04x\n", GET_OMAP_TYPE);
+}
+
+static ssize_t espresso_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 espresso_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 espresso_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 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 espresso_soc_type_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%s\n", omap_types[omap_type()]);
+}
+
+#define ESPRESSO_ATTR_RO(_type, _name, _show) \
+ struct kobj_attribute espresso_##_type##_prop_attr_##_name = \
+ __ATTR(_name, S_IRUGO, _show, NULL)
+
+static ESPRESSO_ATTR_RO(soc, family, espresso_soc_family_show);
+static ESPRESSO_ATTR_RO(soc, revision, espresso_soc_revision_show);
+static ESPRESSO_ATTR_RO(soc, type, espresso_soc_type_show);
+static ESPRESSO_ATTR_RO(soc, die_id, espresso_soc_die_id_show);
+static ESPRESSO_ATTR_RO(soc, production_id, espresso_soc_prod_id_show);
+
+static struct attribute *espresso_soc_prop_attrs[] = {
+ &espresso_soc_prop_attr_family.attr,
+ &espresso_soc_prop_attr_revision.attr,
+ &espresso_soc_prop_attr_type.attr,
+ &espresso_soc_prop_attr_die_id.attr,
+ &espresso_soc_prop_attr_production_id.attr,
+ NULL,
+};
+
+static struct attribute_group espresso_soc_prop_attr_group = {
+ .attrs = espresso_soc_prop_attrs,
+};
+
+static ssize_t espresso_board_revision_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ return sprintf(buf, "0x%02x\n", system_rev);
+}
+
+static ssize_t espresso_board_type_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ return sprintf(buf, "espresso%s%s", board_is_espresso10() ? "10" : "",
+ board_has_modem() ? "" : "wifi");
+}
+
+static ESPRESSO_ATTR_RO(board, revision, espresso_board_revision_show);
+static ESPRESSO_ATTR_RO(board, type, espresso_board_type_show);
+static struct attribute *espresso_board_prop_attrs[] = {
+ &espresso_board_prop_attr_revision.attr,
+ &espresso_board_prop_attr_type.attr,
+ NULL,
+};
+
+static struct attribute_group espresso_board_prop_attr_group = {
+ .attrs = espresso_board_prop_attrs,
+};
+
+static void __init omap4_espresso_create_board_props(void)
+{
+ struct kobject *board_props_kobj;
+ struct kobject *soc_kobj = NULL;
+ 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, &espresso_board_prop_attr_group);
+ if (ret)
+ goto err_board_sysfs_create;
+
+ ret = sysfs_create_group(soc_kobj, &espresso_soc_prop_attr_group);
+ if (ret)
+ goto err_soc_sysfs_create;
+
+ return;
+
+err_soc_sysfs_create:
+ sysfs_remove_group(board_props_kobj, &espresso_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");
+}
+
+static void __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");
+}
+
+static void __init espresso_init(void)
+{
+ omap4_mux_init(NULL, NULL, OMAP_PACKAGE_CBS);
+
+ omap4_espresso_emif_init();
+
+ if (board_is_espresso10()) {
+ espresso10_update_board_type();
+ if (board_is_bestbuy_variant() && system_rev >= 7)
+ sec_muxtbl_init(SEC_MACHINE_ESPRESSO10_USA_BBY, system_rev);
+ sec_muxtbl_init(SEC_MACHINE_ESPRESSO10, system_rev);
+ } else
+ sec_muxtbl_init(SEC_MACHINE_ESPRESSO, system_rev);
+
+ register_reboot_notifier(&espresso_reboot_notifier);
+
+ /* initialize sec common infrastructures */
+ sec_common_init();
+
+ /* initialize board props */
+ omap4_espresso_create_board_props();
+
+ /* initialize each drivers */
+ omap4_espresso_serial_init();
+ omap4_espresso_charger_init();
+ omap4_espresso_pmic_init();
+#ifdef CONFIG_ION_OMAP
+ omap4_register_ion();
+#endif
+ platform_add_devices(espresso_devices, ARRAY_SIZE(espresso_devices));
+ omap_dmm_init();
+ omap4_espresso_sdio_init();
+ usb_musb_init(&musb_board_data);
+ omap4_espresso_connector_init();
+ omap4_espresso_display_init();
+ omap4_espresso_input_init();
+ omap4_espresso_wifi_init();
+ omap4_espresso_sensors_init();
+ omap4_espresso_jack_init();
+ omap4_espresso_none_modem_init();
+
+#ifdef CONFIG_OMAP_HSI_DEVICE
+ /* Allow HSI omap_device to be registered later */
+ omap_hsi_allow_registration();
+#endif
+}
+
+static void __init espresso_map_io(void)
+{
+ omap2_set_globals_443x();
+ omap44xx_map_common_io();
+}
+
+static void omap4_espresso_init_carveout_sizes(
+ struct omap_ion_platform_data *ion)
+{
+ ion->tiler1d_size = (SZ_1M * 14);
+ /* WFD is not supported in espresso So the size is zero */
+ ion->secure_output_wfdhdcp_size = 0;
+ ion->ducati_heap_size = (SZ_1M * 65);
+#ifndef CONFIG_ION_OMAP_TILER_DYNAMIC_ALLOC
+ if (board_is_espresso10())
+ ion->nonsecure_tiler2d_size = (SZ_1M * 19);
+ else
+ ion->nonsecure_tiler2d_size = (SZ_1M * 8);
+ ion->tiler2d_size = (SZ_1M * 81);
+#endif
+}
+
+static void __init espresso_reserve(void)
+{
+#ifdef CONFIG_ION_OMAP
+ omap_init_ram_size();
+ omap4_espresso_memory_display_init();
+ omap4_espresso_init_carveout_sizes(get_omap_ion_platform_data());
+ omap_ion_init();
+#endif
+ /* do the static reservations first */
+#ifdef CONFIG_OMAP_RAM_CONSOLE
+ omap_ram_console_init(ESPRESSO_RAM_CONSOLE_START,
+ OMAP_RAM_CONSOLE_SIZE_DEFAULT);
+#endif
+ memblock_remove(PHYS_ADDR_SMC_MEM, PHYS_ADDR_SMC_SIZE);
+ memblock_remove(PHYS_ADDR_DUCATI_MEM, PHYS_ADDR_DUCATI_SIZE);
+
+ /* ipu needs to recognize secure input buffer area as well */
+ omap_ipu_set_static_mempool(PHYS_ADDR_DUCATI_MEM,
+ PHYS_ADDR_DUCATI_SIZE +
+ OMAP4_ION_HEAP_SECURE_INPUT_SIZE +
+ OMAP4_ION_HEAP_SECURE_OUTPUT_WFDHDCP_SIZE);
+ omap_reserve();
+}
+
+MACHINE_START(OMAP4_ESPRESSO, "OMAP4 Espresso board")
+ /* Maintainer: Daniel Jarai */
+ .boot_params = 0x80000100,
+ .reserve = espresso_reserve,
+ .map_io = espresso_map_io,
+ .init_early = espresso_init_early,
+ .init_irq = gic_init_irq,
+ .init_machine = espresso_init,
+ .timer = &omap_timer,
+MACHINE_END
diff --git a/arch/arm/mach-omap2/board-espresso.h b/arch/arm/mach-omap2/board-espresso.h
new file mode 100644
index 0000000..74a0aa7
--- /dev/null
+++ b/arch/arm/mach-omap2/board-espresso.h
@@ -0,0 +1,94 @@
+/* arch/arm/mach-omap2/board-espresso.h
+ *
+ * Copyright (C) 2011 Samsung Electronics Co, Ltd.
+ *
+ * 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 __BOARD_ESPRESSO_H__
+#define __BOARD_ESPRESSO_H__
+
+#include <linux/serial_core.h>
+
+extern struct class *sec_class;
+
+#define SEC_MACHINE_ESPRESSO 0x01
+#define SEC_MACHINE_ESPRESSO10 0x02
+#define SEC_MACHINE_ESPRESSO10_USA_BBY 0x06
+
+enum espresso_adc_ch {
+ REMOTE_SENSE = 0,
+ ADC_CHECK_1, /* TA detection */
+ ACCESSORY_ID, /* OTG detection */
+ EAR_ADC_35, /* Earjack detection */
+};
+
+bool board_is_espresso10(void);
+bool board_has_modem(void);
+bool board_is_bestbuy_variant(void);
+
+/** @category common */
+unsigned int omap4_espresso_get_board_type(void);
+
+/** @category LCD, HDMI */
+void omap4_espresso_display_init(void);
+void omap4_espresso_memory_display_init(void);
+
+/** @category LCD */
+void __init omap4_espresso_display_early_init(void);
+
+/** @category Key, TSP, Touch-Key */
+void omap4_espresso_input_init(void);
+void omap4_espresso_tsp_ta_detect(int);
+
+/** @category Jack, Dock */
+void omap4_espresso_jack_init(void);
+
+/** @category Charger, Battery */
+void omap4_espresso_power_init(void);
+
+/** @category Motion Sensor */
+void omap4_espresso_sensors_init(void);
+void omap4_espresso_set_chager_type(int type);
+
+/** @category mUSB-IC, MHL */
+void omap4_espresso_connector_init(void);
+int omap4_espresso_get_adc(enum espresso_adc_ch ch);
+void omap4_espresso_usb_detected(int cable_type);
+
+/** @category LPDDR2 */
+void omap4_espresso_emif_init(void);
+
+/** @category TWL6030, TWL6040 */
+void omap4_espresso_pmic_init(void);
+
+/** @category I2C, UART(GPS) */
+void omap4_espresso_serial_init(void);
+
+/** @category MMCHS, WiFi */
+void omap4_espresso_sdio_init(void);
+extern struct mmc_platform_data espresso_wifi_data;
+
+/** @category WiFi */
+void omap4_espresso_wifi_init(void);
+
+/** @category Bluetooth */
+void bcm_bt_lpm_exit_lpm_locked(struct uart_port *uport);
+
+/** @category charger */
+void omap4_espresso_charger_init(void);
+
+/** @category modem*/
+void omap4_espresso_none_modem_init(void);
+
+void check_jig_status(int status);
+
+void notify_dock_status(int status);
+#endif /* __BOARD_ESPRESSO_H__ */