diff options
author | Andreas Blaesius <skate4life@gmx.de> | 2016-05-05 13:50:13 +0200 |
---|---|---|
committer | Andreas Blaesius <skate4life@gmx.de> | 2016-05-05 14:11:40 +0200 |
commit | 71eb4db060a0b5ab35372886a792f41cce53b866 (patch) | |
tree | eb3acabd5d2389ef95142f8fbef3affed5bfc627 /arch | |
parent | cb882a014352e9c57493ba29c93dbdee57f7b663 (diff) | |
download | kernel_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')
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__ */ |