blob: c002202b89c545b18710f11a9055c84de7a4c97f [file] [log] [blame]
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/gpio_keys.h>
#include <linux/init.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/spinlock.h>
#include <asm/coremem.h>
#include <asm/mach/arch.h>
#include <asm/soc-tz1090/defs.h>
#include <asm/soc-tz1090/pdc.h>
#include <asm/soc-tz1090/pm.h>
#include <asm/soc-tz1090/setup.h>
#include <asm/soc-tz1090/usb.h>
#include "gpio.h"
#include "poweroff.h"
#include "setup.h"
#define GPIO_KEY_DEBOUNCE_MSEC 5 /* ms */
/* No XTAL3 (32.768KHz) oscillator is fitted */
unsigned long get_xtal3(void)
{
return 0;
}
/*
* Backlight is powered by boost converter on USB power switch chip. and must be
* turned on for VBUS to be powered.
*/
static DEFINE_SPINLOCK(bl_boost_lock);
#define POLARIS_BL_BOOST_SETUP_M (1 << 31)
static unsigned int bl_boost_users;
static int polaris_bl_boost_setup(void)
{
unsigned long flags;
int err = 0;
spin_lock_irqsave(&bl_boost_lock, flags);
/* is it already set up? */
if (bl_boost_users & POLARIS_BL_BOOST_SETUP_M)
goto out;
/* get control of EN_TFT_BL */
err = gpio_request(EN_TFT_BL, "EN_TFT_BL");
if (err) {
pr_err("Couldn't get EN_TFT_BL gpio!\n");
goto out;
}
err = gpio_direction_output(EN_TFT_BL, 1);
if (err) {
pr_err("Couldn't make EN_TFT_BL an output!\n");
gpio_free(EN_TFT_BL);
goto out;
}
/* record that the GPIO is configured */
bl_boost_users |= POLARIS_BL_BOOST_SETUP_M;
out:
spin_unlock_irqrestore(&bl_boost_lock, flags);
return err;
}
int polaris_bl_boost_set(unsigned int user, int en)
{
unsigned long flags;
int ret;
if (user >= 31)
return -EINVAL;
/* ensure backlight is setup */
ret = polaris_bl_boost_setup();
spin_lock_irqsave(&bl_boost_lock, flags);
if (en)
bl_boost_users |= (1 << user);
else
bl_boost_users &= ~(1 << user);
/* update backlight boost power */
if (!ret)
gpio_set_value(EN_TFT_BL,
bl_boost_users & ~POLARIS_BL_BOOST_SETUP_M);
spin_unlock_irqrestore(&bl_boost_lock, flags);
return ret;
}
/*------------------------------------ USB/VBUS ------------------------------*/
static void polaris_enable_vbus(void)
{
polaris_bl_boost_set(POLARIS_BL_BOOST_VBUS, 1);
gpio_set_value(EN_VBUS, 1);
}
static void polaris_disable_vbus(void)
{
gpio_set_value(EN_VBUS, 0);
polaris_bl_boost_set(POLARIS_BL_BOOST_VBUS, 0);
}
static struct dwc_otg_board polaris_usb_board = {
.enable_vbus = polaris_enable_vbus,
.disable_vbus = polaris_disable_vbus,
};
static int __init polaris_init_usb(void)
{
if (gpio_request(EN_VBUS, "EN_VBUS"))
pr_err("Failed to request EN_VBUS GPIO\n");
gpio_direction_output(EN_VBUS, 1);
comet_usb_setup(&polaris_usb_board);
return 0;
}
/*--------------------------- GPIO Buttons -----------------------------------*/
static struct gpio_keys_button polaris_gpio_buttons[] = {
{
.code = KEY_VOLUMEDOWN,
.gpio = GPIO_PLL_ON,
.desc = "Vol-",
.type = EV_KEY,
.debounce_interval = GPIO_KEY_DEBOUNCE_MSEC,
.can_disable = true,
},
{
.code = KEY_VOLUMEUP,
.gpio = GPIO_PA_ON,
.desc = "Vol+",
.type = EV_KEY,
.debounce_interval = GPIO_KEY_DEBOUNCE_MSEC,
.can_disable = true,
},
{
.code = KEY_POWER,
.gpio = GPIO_SYS_WAKE0,
.desc = "Power",
.type = EV_KEY,
.wakeup = true,
.debounce_interval = GPIO_KEY_DEBOUNCE_MSEC,
.can_disable = true,
},
};
static struct gpio_keys_platform_data polaris_gpio_buttons_data = {
.buttons = polaris_gpio_buttons,
.nbuttons = ARRAY_SIZE(polaris_gpio_buttons),
.rep = false, /* enable auto repeat */
};
static struct platform_device polaris_gpio_buttons_device = {
.name = "gpio-keys",
.dev = {
.platform_data = &polaris_gpio_buttons_data,
}
};
static int __init polaris_init_gpio_buttons(void)
{
int err;
err = platform_device_register(&polaris_gpio_buttons_device);
if (err) {
pr_err("gpio-keys: register failed: %d\n", err);
return err;
}
return 0;
}
/*--------------------------- power management -------------------------------*/
static void polaris_power_off(void)
{
struct metag_coremem_region *reg;
void (*power_off_func)(void);
unsigned long flags;
/*
* Ensure power button is set as wake.
*/
enable_irq_wake(gpio_to_irq(GPIO_SYS_WAKE0));
/*
* Increase delay after reset and power on for the external regulators.
* 0x7 = 128 clock cycles (32kHz clock domain).
*/
writel(0x07777777, PDC_BASE_ADDR + PDC_SOC_DELAY);
/*
* Cutting +1v8 power supply kills RAM, so we need to ensure no RAM
* accesses occur after this is done. This is guaranteed by executing a
* stub of assembly code from locked in cache lines.
*/
/* Get the address of some core memory */
reg = metag_coremem_alloc(METAG_COREMEM_ICACHE,
polaris_raw_power_off_sz);
if (!reg) {
pr_err("Couldn't allocate core memory for power off\n");
return;
}
/* Copy the power off code into core memory */
power_off_func = metag_coremem_push(reg, polaris_raw_power_off,
polaris_raw_power_off_sz);
if (!power_off_func) {
pr_err("Couldn't push power off function to core memory\n");
metag_coremem_free(reg);
return;
}
/* Run the poweroff code, with other threads stopped */
__global_lock2(flags);
wmb();
power_off_func();
/* polaris_raw_power_off() should never return */
BUG();
}
#ifdef CONFIG_PM_SLEEP
static int polaris_suspend(suspend_state_t state)
{
/*
* Increase delay after reset and power on for the external regulators.
* 0x7 = 128 clock cycles (32kHz clock domain).
*/
writel(0x07777777, PDC_BASE_ADDR + PDC_SOC_DELAY);
/*
* Kill 3v3 supply.
*/
gpio_direction_output(KILL_3V3_MAIN, 1);
udelay(1000);
gpio_direction_output(KILL_3V3_MAIN, 0);
return 0;
}
static void polaris_resume(suspend_state_t state)
{
/*
* Standby won't restore 3v3 because EXT_POWER doesn't change, so use
* LATCH_3V3_MAIN to turn it back on again.
*/
if (state == PM_SUSPEND_STANDBY) {
gpio_direction_output(LATCH_3V3_MAIN, 1);
udelay(5000);
gpio_direction_output(LATCH_3V3_MAIN, 0);
}
}
#endif /* CONFIG_PM_SLEEP */
static void polaris_init_pm(void)
{
int kill_1v8_err, kill_3v3_err, latch_3v3_err;
/* Request power kill GPIOs */
kill_1v8_err = gpio_request(KILL_1V8, "KILL_1V8");
if (kill_1v8_err) {
pr_err("%s: Could not get KILL_1V8 GPIO", __func__);
goto err_kill_1v8;
}
kill_3v3_err = gpio_request(KILL_3V3_MAIN, "KILL_3V3_MAIN");
if (kill_3v3_err) {
pr_err("%s: Could not get KILL_3V3_MAIN GPIO", __func__);
goto err_kill_3v3;
}
latch_3v3_err = gpio_request(LATCH_3V3_MAIN, "LATCH_3V3_MAIN");
if (latch_3v3_err) {
pr_err("%s: Could not get LATCH_3V3_MAIN GPIO", __func__);
goto err_latch_3v3;
}
/* Register board callbacks */
board_power_off = polaris_power_off;
#ifdef CONFIG_PM_SLEEP
board_suspend = polaris_suspend;
board_resume = polaris_resume;
#endif
return;
err_latch_3v3:
gpio_free(KILL_3V3_MAIN);
err_kill_3v3:
gpio_free(KILL_1V8);
err_kill_1v8:
return;
}
/*--------------------------- Init -------------------------------------------*/
static void __init polaris_init(void)
{
comet_init_machine();
polaris_init_gpio_buttons();
polaris_init_usb();
polaris_init_pm();
}
/* PURE Polaris */
static const char *polaris_boards_compat[] __initdata = {
"img,tz1090-01xk",
NULL,
};
MACHINE_START(PURE_01XK, "01XK PURE Polaris")
.dt_compat = polaris_boards_compat,
TZ1090_MACHINE_DEFAULTS,
.init_machine = polaris_init,
MACHINE_END