linux/arch/arm/mach-omap2/board-zoom-peripherals.c
Tony Lindgren 3b972bf06c ARM: OMAP2+: Split omap2_hsmmc_init() to properly support I2C GPIO pins
Otherwise omap_device_build() and omap_mux related functions
can't be marked as __init when twl is build as a module.

If a board is using GPIO pins or regulators configured by an
external chip, such as TWL PMIC on I2C bus, the board must
mark those MMC controllers as deferred. Additionally both
omap_hsmmc_init() and omap_hsmmc_late_init() must be called
by the board.

For MMC controllers using internal GPIO pins for card
detect and regulators the slots don't need to be marked
deferred. In this case calling omap_hsmmc_init() is sufficient.

Only mark the MMC slots using gpio_cd or gpio_wd as deferred
as noted by Igor Grinberg <grinberg@compulab.co.il>.

Note that this patch does not change the behaviour for
board-4430sdp.c board-omap4panda.c. These boards wrongly
rely on the omap_hsmmc.c init function callback to configure
the PMIC GPIO interrupt lines on external chip. If the PMIC
interrupt lines are not configured during init, they will
fail.

Reported-by: Russell King <rmk+kernel@arm.linux.org.uk>
Signed-off-by: Rajendra Nayak <rnayak@ti.com>
Signed-off-by: Tony Lindgren <tony@atomide.com>
2012-02-20 10:00:39 -08:00

311 lines
7.6 KiB
C

/*
* Copyright (C) 2009 Texas Instruments Inc.
*
* Modified from mach-omap2/board-zoom2.c
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/input/matrix_keypad.h>
#include <linux/gpio.h>
#include <linux/i2c/twl.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/fixed.h>
#include <linux/wl12xx.h>
#include <linux/mmc/host.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include "common.h"
#include <plat/usb.h>
#include <mach/board-zoom.h>
#include "mux.h"
#include "hsmmc.h"
#include "common-board-devices.h"
#define OMAP_ZOOM_WLAN_PMENA_GPIO (101)
#define OMAP_ZOOM_WLAN_IRQ_GPIO (162)
#define LCD_PANEL_ENABLE_GPIO (7 + OMAP_MAX_GPIO_LINES)
/* Zoom2 has Qwerty keyboard*/
static uint32_t board_keymap[] = {
KEY(0, 0, KEY_E),
KEY(0, 1, KEY_R),
KEY(0, 2, KEY_T),
KEY(0, 3, KEY_HOME),
KEY(0, 6, KEY_I),
KEY(0, 7, KEY_LEFTSHIFT),
KEY(1, 0, KEY_D),
KEY(1, 1, KEY_F),
KEY(1, 2, KEY_G),
KEY(1, 3, KEY_SEND),
KEY(1, 6, KEY_K),
KEY(1, 7, KEY_ENTER),
KEY(2, 0, KEY_X),
KEY(2, 1, KEY_C),
KEY(2, 2, KEY_V),
KEY(2, 3, KEY_END),
KEY(2, 6, KEY_DOT),
KEY(2, 7, KEY_CAPSLOCK),
KEY(3, 0, KEY_Z),
KEY(3, 1, KEY_KPPLUS),
KEY(3, 2, KEY_B),
KEY(3, 3, KEY_F1),
KEY(3, 6, KEY_O),
KEY(3, 7, KEY_SPACE),
KEY(4, 0, KEY_W),
KEY(4, 1, KEY_Y),
KEY(4, 2, KEY_U),
KEY(4, 3, KEY_F2),
KEY(4, 4, KEY_VOLUMEUP),
KEY(4, 6, KEY_L),
KEY(4, 7, KEY_LEFT),
KEY(5, 0, KEY_S),
KEY(5, 1, KEY_H),
KEY(5, 2, KEY_J),
KEY(5, 3, KEY_F3),
KEY(5, 4, KEY_UNKNOWN),
KEY(5, 5, KEY_VOLUMEDOWN),
KEY(5, 6, KEY_M),
KEY(5, 7, KEY_RIGHT),
KEY(6, 0, KEY_Q),
KEY(6, 1, KEY_A),
KEY(6, 2, KEY_N),
KEY(6, 3, KEY_BACKSPACE),
KEY(6, 6, KEY_P),
KEY(6, 7, KEY_UP),
KEY(7, 0, KEY_PROG1), /*MACRO 1 <User defined> */
KEY(7, 1, KEY_PROG2), /*MACRO 2 <User defined> */
KEY(7, 2, KEY_PROG3), /*MACRO 3 <User defined> */
KEY(7, 3, KEY_PROG4), /*MACRO 4 <User defined> */
KEY(7, 6, KEY_SELECT),
KEY(7, 7, KEY_DOWN)
};
static struct matrix_keymap_data board_map_data = {
.keymap = board_keymap,
.keymap_size = ARRAY_SIZE(board_keymap),
};
static struct twl4030_keypad_data zoom_kp_twl4030_data = {
.keymap_data = &board_map_data,
.rows = 8,
.cols = 8,
.rep = 1,
};
static struct regulator_consumer_supply zoom_vmmc1_supply[] = {
REGULATOR_SUPPLY("vmmc", "omap_hsmmc.0"),
};
static struct regulator_consumer_supply zoom_vsim_supply[] = {
REGULATOR_SUPPLY("vmmc_aux", "omap_hsmmc.0"),
};
static struct regulator_consumer_supply zoom_vmmc2_supply[] = {
REGULATOR_SUPPLY("vmmc", "omap_hsmmc.1"),
};
static struct regulator_consumer_supply zoom_vmmc3_supply[] = {
REGULATOR_SUPPLY("vmmc", "omap_hsmmc.2"),
};
/* VMMC1 for OMAP VDD_MMC1 (i/o) and MMC1 card */
static struct regulator_init_data zoom_vmmc1 = {
.constraints = {
.min_uV = 1850000,
.max_uV = 3150000,
.valid_modes_mask = REGULATOR_MODE_NORMAL
| REGULATOR_MODE_STANDBY,
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE
| REGULATOR_CHANGE_MODE
| REGULATOR_CHANGE_STATUS,
},
.num_consumer_supplies = ARRAY_SIZE(zoom_vmmc1_supply),
.consumer_supplies = zoom_vmmc1_supply,
};
/* VMMC2 for MMC2 card */
static struct regulator_init_data zoom_vmmc2 = {
.constraints = {
.min_uV = 1850000,
.max_uV = 1850000,
.apply_uV = true,
.valid_modes_mask = REGULATOR_MODE_NORMAL
| REGULATOR_MODE_STANDBY,
.valid_ops_mask = REGULATOR_CHANGE_MODE
| REGULATOR_CHANGE_STATUS,
},
.num_consumer_supplies = ARRAY_SIZE(zoom_vmmc2_supply),
.consumer_supplies = zoom_vmmc2_supply,
};
/* VSIM for OMAP VDD_MMC1A (i/o for DAT4..DAT7) */
static struct regulator_init_data zoom_vsim = {
.constraints = {
.min_uV = 1800000,
.max_uV = 3000000,
.valid_modes_mask = REGULATOR_MODE_NORMAL
| REGULATOR_MODE_STANDBY,
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE
| REGULATOR_CHANGE_MODE
| REGULATOR_CHANGE_STATUS,
},
.num_consumer_supplies = ARRAY_SIZE(zoom_vsim_supply),
.consumer_supplies = zoom_vsim_supply,
};
static struct regulator_init_data zoom_vmmc3 = {
.constraints = {
.valid_ops_mask = REGULATOR_CHANGE_STATUS,
},
.num_consumer_supplies = ARRAY_SIZE(zoom_vmmc3_supply),
.consumer_supplies = zoom_vmmc3_supply,
};
static struct fixed_voltage_config zoom_vwlan = {
.supply_name = "vwl1271",
.microvolts = 1800000, /* 1.8V */
.gpio = OMAP_ZOOM_WLAN_PMENA_GPIO,
.startup_delay = 70000, /* 70msec */
.enable_high = 1,
.enabled_at_boot = 0,
.init_data = &zoom_vmmc3,
};
static struct platform_device omap_vwlan_device = {
.name = "reg-fixed-voltage",
.id = 1,
.dev = {
.platform_data = &zoom_vwlan,
},
};
static struct wl12xx_platform_data omap_zoom_wlan_data __initdata = {
.irq = OMAP_GPIO_IRQ(OMAP_ZOOM_WLAN_IRQ_GPIO),
/* ZOOM ref clock is 26 MHz */
.board_ref_clock = 1,
};
static struct omap2_hsmmc_info mmc[] = {
{
.name = "external",
.mmc = 1,
.caps = MMC_CAP_4_BIT_DATA,
.gpio_wp = -EINVAL,
.power_saving = true,
.deferred = true,
},
{
.name = "internal",
.mmc = 2,
.caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
.gpio_cd = -EINVAL,
.gpio_wp = -EINVAL,
.nonremovable = true,
.power_saving = true,
},
{
.name = "wl1271",
.mmc = 3,
.caps = MMC_CAP_4_BIT_DATA | MMC_CAP_POWER_OFF_CARD,
.gpio_wp = -EINVAL,
.gpio_cd = -EINVAL,
.nonremovable = true,
},
{} /* Terminator */
};
static int zoom_twl_gpio_setup(struct device *dev,
unsigned gpio, unsigned ngpio)
{
int ret;
/* gpio + 0 is "mmc0_cd" (input/IRQ) */
mmc[0].gpio_cd = gpio + 0;
omap_hsmmc_late_init(mmc);
ret = gpio_request_one(LCD_PANEL_ENABLE_GPIO, GPIOF_OUT_INIT_LOW,
"lcd enable");
if (ret)
pr_err("Failed to get LCD_PANEL_ENABLE_GPIO (gpio%d).\n",
LCD_PANEL_ENABLE_GPIO);
return ret;
}
/* EXTMUTE callback function */
static void zoom2_set_hs_extmute(int mute)
{
gpio_set_value(ZOOM2_HEADSET_EXTMUTE_GPIO, mute);
}
static struct twl4030_gpio_platform_data zoom_gpio_data = {
.gpio_base = OMAP_MAX_GPIO_LINES,
.irq_base = TWL4030_GPIO_IRQ_BASE,
.irq_end = TWL4030_GPIO_IRQ_END,
.setup = zoom_twl_gpio_setup,
};
static struct twl4030_platform_data zoom_twldata = {
/* platform_data for children goes here */
.gpio = &zoom_gpio_data,
.keypad = &zoom_kp_twl4030_data,
.vmmc1 = &zoom_vmmc1,
.vmmc2 = &zoom_vmmc2,
.vsim = &zoom_vsim,
};
static int __init omap_i2c_init(void)
{
omap3_pmic_get_config(&zoom_twldata,
TWL_COMMON_PDATA_USB | TWL_COMMON_PDATA_BCI |
TWL_COMMON_PDATA_MADC | TWL_COMMON_PDATA_AUDIO,
TWL_COMMON_REGULATOR_VDAC | TWL_COMMON_REGULATOR_VPLL2);
if (machine_is_omap_zoom2()) {
struct twl4030_codec_data *codec_data;
codec_data = zoom_twldata.audio->codec;
codec_data->ramp_delay_value = 3; /* 161 ms */
codec_data->hs_extmute = 1;
codec_data->set_hs_extmute = zoom2_set_hs_extmute;
}
omap_pmic_init(1, 2400, "twl5030", INT_34XX_SYS_NIRQ, &zoom_twldata);
omap_register_i2c_bus(2, 400, NULL, 0);
omap_register_i2c_bus(3, 400, NULL, 0);
return 0;
}
static void enable_board_wakeup_source(void)
{
/* T2 interrupt line (keypad) */
omap_mux_init_signal("sys_nirq",
OMAP_WAKEUP_EN | OMAP_PIN_INPUT_PULLUP);
}
void __init zoom_peripherals_init(void)
{
int ret = wl12xx_set_platform_data(&omap_zoom_wlan_data);
if (ret)
pr_err("error setting wl12xx data: %d\n", ret);
omap_hsmmc_init(mmc);
omap_i2c_init();
platform_device_register(&omap_vwlan_device);
usb_musb_init(NULL);
enable_board_wakeup_source();
omap_serial_init();
}