@@ -0,0 +1,395 @@
/* linux/arch/arm/mach-msm/board-saga-mmc.c
*
* Copyright (C) 2008 HTC Corporation.
*
* 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/mmc/host.h>
#include <linux/mmc/sdio_ids.h>
#include <linux/err.h>
#include <linux/debugfs.h>
#include <linux/gpio.h>
#include <linux/mfd/pmic8058.h>

#include <asm/gpio.h>
#include <asm/io.h>

#include <mach/vreg.h>
#include <mach/htc_pwrsink.h>

#include <asm/mach/mmc.h>

#include "devices.h"
#include "board-saga.h"
#include "proc_comm.h"

#define SAGA_SDMC_CD_N_SYS PM8058_GPIO_PM_TO_SYS(SAGA_SDMC_CD_N)

extern int msm_add_sdcc(unsigned int controller, struct mmc_platform_data *plat,
unsigned int stat_irq, unsigned long stat_irq_flags);

/* ---- SDCARD ---- */

static uint32_t sdcard_on_gpio_table[] = {
PCOM_GPIO_CFG(58, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_16MA), /* CLK */
PCOM_GPIO_CFG(59, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), /* CMD */
PCOM_GPIO_CFG(60, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), /* DAT3 */
PCOM_GPIO_CFG(61, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), /* DAT2 */
PCOM_GPIO_CFG(62, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), /* DAT1 */
PCOM_GPIO_CFG(63, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), /* DAT0 */
};

static uint32_t sdcard_off_gpio_table[] = {
PCOM_GPIO_CFG(58, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* CLK */
PCOM_GPIO_CFG(59, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* CMD */
PCOM_GPIO_CFG(60, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT3 */
PCOM_GPIO_CFG(61, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT2 */
PCOM_GPIO_CFG(62, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT1 */
PCOM_GPIO_CFG(63, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT0 */
};

static uint opt_disable_sdcard;

static uint32_t movinand_on_gpio_table[] = {
PCOM_GPIO_CFG(64, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA), /* CLK */
PCOM_GPIO_CFG(65, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA), /* CMD */
PCOM_GPIO_CFG(66, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA), /* DAT3 */
PCOM_GPIO_CFG(67, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA), /* DAT2 */
PCOM_GPIO_CFG(68, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA), /* DAT1 */
PCOM_GPIO_CFG(69, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA), /* DAT0 */
PCOM_GPIO_CFG(115, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA), /* DAT4 */
PCOM_GPIO_CFG(114, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA), /* DAT5 */
PCOM_GPIO_CFG(113, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA), /* DAT6 */
PCOM_GPIO_CFG(112, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA), /* DAT7 */
};
static int __init saga_disablesdcard_setup(char *str)
{
int cal = simple_strtol(str, NULL, 0);

opt_disable_sdcard = cal;
return 1;
}

__setup("board_saga.disable_sdcard=", saga_disablesdcard_setup);

static struct vreg *vreg_sdslot; /* SD slot power */

struct mmc_vdd_xlat {
int mask;
int level;
};

static struct mmc_vdd_xlat mmc_vdd_table[] = {
{ MMC_VDD_28_29, 2850 },
{ MMC_VDD_29_30, 2900 },
};

static unsigned int sdslot_vdd = 0xffffffff;
static unsigned int sdslot_vreg_enabled;

static uint32_t saga_sdslot_switchvdd(struct device *dev, unsigned int vdd)
{
int i;

BUG_ON(!vreg_sdslot);

if (vdd == sdslot_vdd)
return 0;

sdslot_vdd = vdd;

if (vdd == 0) {
printk(KERN_INFO "%s: Disabling SD slot power\n", __func__);
config_gpio_table(sdcard_off_gpio_table,
ARRAY_SIZE(sdcard_off_gpio_table));
vreg_disable(vreg_sdslot);
sdslot_vreg_enabled = 0;
return 0;
}

if (!sdslot_vreg_enabled) {
mdelay(5);
vreg_enable(vreg_sdslot);
udelay(500);
config_gpio_table(sdcard_on_gpio_table,
ARRAY_SIZE(sdcard_on_gpio_table));
sdslot_vreg_enabled = 1;
}

for (i = 0; i < ARRAY_SIZE(mmc_vdd_table); i++) {
if (mmc_vdd_table[i].mask == (1 << vdd)) {
printk(KERN_INFO "%s: Setting level to %u\n",
__func__, mmc_vdd_table[i].level);
vreg_set_level(vreg_sdslot, mmc_vdd_table[i].level);
return 0;
}
}

printk(KERN_ERR "%s: Invalid VDD %d specified\n", __func__, vdd);
return 0;
}

static unsigned int saga_sdslot_status(struct device *dev)
{
unsigned int status;

status = (unsigned int) gpio_get_value(SAGA_SDMC_CD_N_SYS);
return (!status);
}

#define SAGA_MMC_VDD (MMC_VDD_28_29 | MMC_VDD_29_30)

static unsigned int saga_sdslot_type = MMC_TYPE_SD;

static struct mmc_platform_data saga_sdslot_data = {
.ocr_mask = SAGA_MMC_VDD,
.status_irq = MSM_GPIO_TO_INT(SAGA_SDMC_CD_N_SYS),
.status = saga_sdslot_status,
.translate_vdd = saga_sdslot_switchvdd,
.slot_type = &saga_sdslot_type,
.dat0_gpio = 63,
};

static unsigned int saga_emmcslot_type = MMC_TYPE_MMC;
static struct mmc_platform_data saga_movinand_data = {
.ocr_mask = SAGA_MMC_VDD,
.slot_type = &saga_emmcslot_type,
.mmc_bus_width = MMC_CAP_8_BIT_DATA,
};

/* ---- WIFI ---- */

static uint32_t wifi_on_gpio_table[] = {
PCOM_GPIO_CFG(116, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT3 */
PCOM_GPIO_CFG(117, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT2 */
PCOM_GPIO_CFG(118, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT1 */
PCOM_GPIO_CFG(119, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT0 */
PCOM_GPIO_CFG(111, 1, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), /* CMD */
PCOM_GPIO_CFG(110, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA), /* CLK */
PCOM_GPIO_CFG(147, 0, GPIO_INPUT, GPIO_NO_PULL, GPIO_4MA), /* WLAN IRQ */
};

static uint32_t wifi_off_gpio_table[] = {
PCOM_GPIO_CFG(116, 0, GPIO_INPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT3 */
PCOM_GPIO_CFG(117, 0, GPIO_INPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT2 */
PCOM_GPIO_CFG(118, 0, GPIO_INPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT1 */
PCOM_GPIO_CFG(119, 0, GPIO_INPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT0 */
PCOM_GPIO_CFG(111, 0, GPIO_INPUT, GPIO_PULL_UP, GPIO_4MA), /* CMD */
PCOM_GPIO_CFG(110, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* CLK */
PCOM_GPIO_CFG(147, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* WLAN IRQ */
};

/* BCM4329 returns wrong sdio_vsn(1) when we read cccr,
* we use predefined value (sdio_vsn=2) here to initial sdio driver well
*/
static struct embedded_sdio_data saga_wifi_emb_data = {
.cccr = {
.sdio_vsn = 2,
.multi_block = 1,
.low_speed = 0,
.wide_bus = 0,
.high_power = 1,
.high_speed = 1,
},
};

static void (*wifi_status_cb)(int card_present, void *dev_id);
static void *wifi_status_cb_devid;

static int
saga_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 int saga_wifi_cd; /* WiFi virtual 'card detect' status */

static unsigned int saga_wifi_status(struct device *dev)
{
return saga_wifi_cd;
}

static struct mmc_platform_data saga_wifi_data = {
.ocr_mask = MMC_VDD_28_29,
.status = saga_wifi_status,
.register_status_notify = saga_wifi_status_register,
.embedded_sdio = &saga_wifi_emb_data,
};

int saga_wifi_set_carddetect(int val)
{
printk(KERN_INFO "%s: %d\n", __func__, val);
saga_wifi_cd = val;
if (wifi_status_cb)
wifi_status_cb(val, wifi_status_cb_devid);
else
printk(KERN_WARNING "%s: Nobody to notify\n", __func__);
return 0;
}
EXPORT_SYMBOL(saga_wifi_set_carddetect);

static struct pm8058_gpio pmic_gpio_sleep_clk_output = {
.direction = PM_GPIO_DIR_OUT,
.output_buffer = PM_GPIO_OUT_BUF_CMOS,
.output_value = 0,
.pull = PM_GPIO_PULL_NO,
.vin_sel = PM_GPIO_VIN_S3, /* S3 1.8 V */
.out_strength = PM_GPIO_STRENGTH_HIGH,
.function = PM_GPIO_FUNC_2,
};

#define ID_WIFI 0
#define ID_BT 1
#define CLK_OFF 0
#define CLK_ON 1
static DEFINE_SPINLOCK(saga_w_b_slock);
int saga_sleep_clk_state_wifi = CLK_OFF;
int saga_sleep_clk_state_bt = CLK_OFF;

int saga_wifi_bt_sleep_clk_ctl(int on, int id)
{
int err = 0;
unsigned long flags;

printk(KERN_DEBUG "%s ON=%d, ID=%d\n", __func__, on, id);

spin_lock_irqsave(&saga_w_b_slock, flags);
if (on) {
if ((CLK_OFF == saga_sleep_clk_state_wifi)
&& (CLK_OFF == saga_sleep_clk_state_bt)) {
printk(KERN_DEBUG "EN SLEEP CLK\n");
pmic_gpio_sleep_clk_output.function = PM_GPIO_FUNC_2;
err = pm8058_gpio_config(SAGA_WIFI_SLOW_CLK,
&pmic_gpio_sleep_clk_output);
if (err) {
spin_unlock_irqrestore(&saga_w_b_slock,
flags);
printk(KERN_ERR "ERR EN SLEEP CLK, ERR=%d\n",
err);
return err;
}
}

if (id == ID_BT)
saga_sleep_clk_state_bt = CLK_ON;
else
saga_sleep_clk_state_wifi = CLK_ON;
} else {
if (((id == ID_BT) && (CLK_OFF == saga_sleep_clk_state_wifi))
|| ((id == ID_WIFI)
&& (CLK_OFF == saga_sleep_clk_state_bt))) {
printk(KERN_DEBUG "DIS SLEEP CLK\n");
pmic_gpio_sleep_clk_output.function =
PM_GPIO_FUNC_NORMAL;
err = pm8058_gpio_config(
SAGA_WIFI_SLOW_CLK,
&pmic_gpio_sleep_clk_output);
if (err) {
spin_unlock_irqrestore(&saga_w_b_slock,
flags);
printk(KERN_ERR "ERR DIS SLEEP CLK, ERR=%d\n",
err);
return err;
}
} else {
printk(KERN_DEBUG "KEEP SLEEP CLK ALIVE\n");
}

if (id)
saga_sleep_clk_state_bt = CLK_OFF;
else
saga_sleep_clk_state_wifi = CLK_OFF;
}
spin_unlock_irqrestore(&saga_w_b_slock, flags);

return 0;
}
EXPORT_SYMBOL(saga_wifi_bt_sleep_clk_ctl);

int saga_wifi_power(int on)
{
printk(KERN_INFO "%s: %d\n", __func__, on);

if (on) {
config_gpio_table(wifi_on_gpio_table,
ARRAY_SIZE(wifi_on_gpio_table));
} else {
config_gpio_table(wifi_off_gpio_table,
ARRAY_SIZE(wifi_off_gpio_table));
}

saga_wifi_bt_sleep_clk_ctl(on, ID_WIFI);
gpio_set_value(SAGA_GPIO_WIFI_SHUTDOWN_N, on); /* WIFI_SHUTDOWN */

mdelay(120);
return 0;
}
EXPORT_SYMBOL(saga_wifi_power);

int saga_wifi_reset(int on)
{
printk(KERN_INFO "%s: do nothing\n", __func__);
return 0;
}

int __init saga_init_mmc(unsigned int sys_rev)
{
uint32_t id;
wifi_status_cb = NULL;
sdslot_vreg_enabled = 0;

printk(KERN_INFO "saga: %s\n", __func__);
/* SDC2: MoviNAND */
register_msm_irq_mask(INT_SDC2_0);
register_msm_irq_mask(INT_SDC2_1);
config_gpio_table(movinand_on_gpio_table,
ARRAY_SIZE(movinand_on_gpio_table));
msm_add_sdcc(2, &saga_movinand_data, 0, 0);

/* initial WIFI_SHUTDOWN# */
id = PCOM_GPIO_CFG(SAGA_GPIO_WIFI_SHUTDOWN_N, 0, GPIO_OUTPUT,
GPIO_NO_PULL, GPIO_2MA),
msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &id, 0);
gpio_set_value(SAGA_GPIO_WIFI_SHUTDOWN_N, 0);

msm_add_sdcc(3, &saga_wifi_data, 0, 0);

register_msm_irq_mask(INT_SDC4_0);
register_msm_irq_mask(INT_SDC4_1);
/* SDCC4: SD card */
if (opt_disable_sdcard) {
printk(KERN_INFO "saga: SD-Card interface disabled\n");
goto done;
}

vreg_sdslot = vreg_get(0, "gp10");
if (IS_ERR(vreg_sdslot))
return PTR_ERR(vreg_sdslot);

set_irq_wake(MSM_GPIO_TO_INT(SAGA_SDMC_CD_N_SYS), 1);

msm_add_sdcc(4, &saga_sdslot_data,
MSM_GPIO_TO_INT(SAGA_SDMC_CD_N_SYS),
IORESOURCE_IRQ_LOWEDGE | IORESOURCE_IRQ_HIGHEDGE);

done:

return 0;
}

Large diffs are not rendered by default.

@@ -0,0 +1,397 @@
/*
* Copyright (C) 2009 Google, Inc.
* Copyright (C) 2009 HTC Corporation.
*
* 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.
*
*/

/* Control bluetooth power for saga platform */

#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/rfkill.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <asm/mach-types.h>

#include "gpio_chip.h"
#include "proc_comm.h"
#include "board-saga.h"

#define ID_BT 1
#define CLK_OFF 0
#define CLK_ON 1

static struct rfkill *bt_rfk;
static const char bt_name[] = "bcm4329";

extern int saga_wifi_bt_sleep_clk_ctl(int on, int id);

/* bt initial configuration */
static uint32_t saga_bt_init_table[] = {

/* BT_RTS */
PCOM_GPIO_CFG(SAGA_GPIO_BT_UART1_RTS,
0,
GPIO_OUTPUT,
GPIO_NO_PULL,
GPIO_8MA),
/* BT_CTS */
PCOM_GPIO_CFG(SAGA_GPIO_BT_UART1_CTS,
0,
GPIO_INPUT,
GPIO_NO_PULL,
GPIO_8MA),
/* BT_RX */
PCOM_GPIO_CFG(SAGA_GPIO_BT_UART1_RX,
0,
GPIO_INPUT,
GPIO_PULL_UP,
GPIO_8MA),
/* BT_TX */
PCOM_GPIO_CFG(SAGA_GPIO_BT_UART1_TX,
0,
GPIO_OUTPUT,
GPIO_NO_PULL,
GPIO_8MA),

/* BT_SHUTDOWN_N */
PCOM_GPIO_CFG(SAGA_GPIO_BT_SHUTDOWN_N,
0,
GPIO_OUTPUT,
GPIO_NO_PULL,
GPIO_4MA),
/* BT_RESET_N */
PCOM_GPIO_CFG(SAGA_GPIO_BT_RESET_N,
0,
GPIO_OUTPUT,
GPIO_NO_PULL,
GPIO_4MA),

/* BT_HOST_WAKE */
PCOM_GPIO_CFG(SAGA_GPIO_BT_HOST_WAKE,
0,
GPIO_INPUT,
GPIO_PULL_UP,
GPIO_4MA),
/* BT_CHIP_WAKE */
PCOM_GPIO_CFG(SAGA_GPIO_BT_CHIP_WAKE,
0,
GPIO_OUTPUT,
GPIO_NO_PULL,
GPIO_4MA),
};

/* bt on configuration */
static uint32_t saga_bt_on_table[] = {

/* BT_RTS */
PCOM_GPIO_CFG(SAGA_GPIO_BT_UART1_RTS,
1,
GPIO_OUTPUT,
GPIO_NO_PULL,
GPIO_8MA),
/* BT_CTS */
PCOM_GPIO_CFG(SAGA_GPIO_BT_UART1_CTS,
1,
GPIO_INPUT,
GPIO_PULL_UP,
GPIO_8MA),
/* BT_RX */
PCOM_GPIO_CFG(SAGA_GPIO_BT_UART1_RX,
1,
GPIO_INPUT,
GPIO_PULL_UP,
GPIO_8MA),
/* BT_TX */
PCOM_GPIO_CFG(SAGA_GPIO_BT_UART1_TX,
1,
GPIO_OUTPUT,
GPIO_NO_PULL,
GPIO_8MA),

/* BT_HOST_WAKE */
PCOM_GPIO_CFG(SAGA_GPIO_BT_HOST_WAKE,
0,
GPIO_INPUT,
GPIO_NO_PULL,
GPIO_4MA),
/* BT_CHIP_WAKE */
PCOM_GPIO_CFG(SAGA_GPIO_BT_CHIP_WAKE,
0,
GPIO_OUTPUT,
GPIO_NO_PULL,
GPIO_4MA),

/* BT_RESET_N */
PCOM_GPIO_CFG(SAGA_GPIO_BT_RESET_N,
0,
GPIO_OUTPUT,
GPIO_NO_PULL,
GPIO_4MA),
/* BT_SHUTDOWN_N */
PCOM_GPIO_CFG(SAGA_GPIO_BT_SHUTDOWN_N,
0,
GPIO_OUTPUT,
GPIO_NO_PULL,
GPIO_4MA),
};

/* bt off configuration */
static uint32_t saga_bt_off_table[] = {

/* BT_RTS */
PCOM_GPIO_CFG(SAGA_GPIO_BT_UART1_RTS,
0,
GPIO_OUTPUT,
GPIO_NO_PULL,
GPIO_8MA),
/* BT_CTS */
PCOM_GPIO_CFG(SAGA_GPIO_BT_UART1_CTS,
0,
GPIO_INPUT,
GPIO_PULL_UP,
GPIO_8MA),
/* BT_RX */
PCOM_GPIO_CFG(SAGA_GPIO_BT_UART1_RX,
0,
GPIO_INPUT,
GPIO_PULL_UP,
GPIO_8MA),
/* BT_TX */
PCOM_GPIO_CFG(SAGA_GPIO_BT_UART1_TX,
0,
GPIO_OUTPUT,
GPIO_NO_PULL,
GPIO_8MA),

/* BT_RESET_N */
PCOM_GPIO_CFG(SAGA_GPIO_BT_RESET_N,
0,
GPIO_OUTPUT,
GPIO_NO_PULL,
GPIO_4MA),
/* BT_SHUTDOWN_N */
PCOM_GPIO_CFG(SAGA_GPIO_BT_SHUTDOWN_N,
0,
GPIO_OUTPUT,
GPIO_NO_PULL,
GPIO_4MA),

/* BT_HOST_WAKE */
PCOM_GPIO_CFG(SAGA_GPIO_BT_HOST_WAKE,
0,
GPIO_INPUT,
GPIO_PULL_UP,
GPIO_4MA),
/* BT_CHIP_WAKE */
PCOM_GPIO_CFG(SAGA_GPIO_BT_CHIP_WAKE,
0,
GPIO_OUTPUT,
GPIO_NO_PULL,
GPIO_4MA),
};

static void config_bt_table(uint32_t *table, int len)
{
int n;
unsigned id;
for (n = 0; n < len; n++) {
id = table[n];
msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &id, 0);
}
}

static void saga_config_bt_init(void)
{
saga_wifi_bt_sleep_clk_ctl(CLK_ON, ID_BT);
mdelay(2);

/* set bt initial configuration*/
config_bt_table(saga_bt_init_table,
ARRAY_SIZE(saga_bt_init_table));
mdelay(5);

/* BT_SHUTDOWN_N */
gpio_configure(SAGA_GPIO_BT_SHUTDOWN_N,
GPIOF_DRIVE_OUTPUT | GPIOF_OUTPUT_HIGH);
mdelay(2);
/* BT_RESET_N */
gpio_configure(SAGA_GPIO_BT_RESET_N,
GPIOF_DRIVE_OUTPUT | GPIOF_OUTPUT_HIGH);
mdelay(15);

/* BT_RESET_N */
gpio_configure(SAGA_GPIO_BT_RESET_N,
GPIOF_DRIVE_OUTPUT | GPIOF_OUTPUT_LOW);
mdelay(2);
/* BT_SHUTDOWN_N */
gpio_configure(SAGA_GPIO_BT_SHUTDOWN_N,
GPIOF_DRIVE_OUTPUT | GPIOF_OUTPUT_LOW);
mdelay(2);

/* BT_RTS */
gpio_configure(SAGA_GPIO_BT_UART1_RTS,
GPIOF_DRIVE_OUTPUT | GPIOF_OUTPUT_HIGH);
/* BT_CTS */

/* BT_RX */

/* BT_TX */
gpio_configure(SAGA_GPIO_BT_UART1_TX,
GPIOF_DRIVE_OUTPUT | GPIOF_OUTPUT_LOW);

/* BT_CHIP_WAKE */
gpio_configure(SAGA_GPIO_BT_CHIP_WAKE,
GPIOF_DRIVE_OUTPUT | GPIOF_OUTPUT_LOW);

}

static void saga_config_bt_on(void)
{
saga_wifi_bt_sleep_clk_ctl(CLK_ON, ID_BT);
mdelay(2);

/* set bt on configuration*/
config_bt_table(saga_bt_on_table,
ARRAY_SIZE(saga_bt_on_table));
mdelay(5);

/* BT_SHUTDOWN_N */
gpio_configure(SAGA_GPIO_BT_SHUTDOWN_N,
GPIOF_DRIVE_OUTPUT | GPIOF_OUTPUT_HIGH);
mdelay(2);

/* BT_RESET_N */
gpio_configure(SAGA_GPIO_BT_RESET_N,
GPIOF_DRIVE_OUTPUT | GPIOF_OUTPUT_HIGH);
mdelay(2);

}

static void saga_config_bt_off(void)
{
/* BT_RESET_N */
gpio_configure(SAGA_GPIO_BT_RESET_N,
GPIOF_DRIVE_OUTPUT | GPIOF_OUTPUT_LOW);
mdelay(2);

/* BT_SHUTDOWN_N */
gpio_configure(SAGA_GPIO_BT_SHUTDOWN_N,
GPIOF_DRIVE_OUTPUT | GPIOF_OUTPUT_LOW);
mdelay(2);

/* set bt off configuration*/
config_bt_table(saga_bt_off_table,
ARRAY_SIZE(saga_bt_off_table));
mdelay(5);

/* BT_RTS */
gpio_configure(SAGA_GPIO_BT_UART1_RTS,
GPIOF_DRIVE_OUTPUT | GPIOF_OUTPUT_LOW);
/* BT_CTS */

/* BT_RX */

/* BT_TX */
gpio_configure(SAGA_GPIO_BT_UART1_TX,
GPIOF_DRIVE_OUTPUT | GPIOF_OUTPUT_LOW);

/* BT_HOST_WAKE */

/* BT_CHIP_WAKE */
gpio_configure(SAGA_GPIO_BT_CHIP_WAKE,
GPIOF_DRIVE_OUTPUT | GPIOF_OUTPUT_LOW);

saga_wifi_bt_sleep_clk_ctl(CLK_OFF, ID_BT);
mdelay(2);
}

static int bluetooth_set_power(void *data, bool blocked)
{
if (!blocked)
saga_config_bt_on();
else
saga_config_bt_off();

return 0;
}

static struct rfkill_ops saga_rfkill_ops = {
.set_block = bluetooth_set_power,
};

static int saga_rfkill_probe(struct platform_device *pdev)
{
int rc = 0;
bool default_state = true; /* off */

saga_config_bt_init(); /* bt gpio initial config */

bluetooth_set_power(NULL, default_state);

bt_rfk = rfkill_alloc(bt_name, &pdev->dev, RFKILL_TYPE_BLUETOOTH,
&saga_rfkill_ops, NULL);
if (!bt_rfk) {
rc = -ENOMEM;
goto err_rfkill_reset;
}

rfkill_set_states(bt_rfk, default_state, false);

/* userspace cannot take exclusive control */
rc = rfkill_register(bt_rfk);
if (rc)
goto err_rfkill_reg;

return 0;

err_rfkill_reg:
rfkill_destroy(bt_rfk);
err_rfkill_reset:
return rc;
}

static int saga_rfkill_remove(struct platform_device *dev)
{
rfkill_unregister(bt_rfk);
rfkill_destroy(bt_rfk);

return 0;
}

static struct platform_driver saga_rfkill_driver = {
.probe = saga_rfkill_probe,
.remove = saga_rfkill_remove,
.driver = {
.name = "saga_rfkill",
.owner = THIS_MODULE,
},
};

int __init saga_rfkill_init(void)
{
if (!machine_is_saga())
return 0;
return platform_driver_register(&saga_rfkill_driver);
}

static void __exit saga_rfkill_exit(void)
{
platform_driver_unregister(&saga_rfkill_driver);
}

module_init(saga_rfkill_init);
module_exit(saga_rfkill_exit);
MODULE_DESCRIPTION("saga rfkill");
MODULE_AUTHOR("Nick Pelly <npelly@google.com>");
MODULE_LICENSE("GPL");
@@ -0,0 +1,155 @@
/* linux/arch/arm/mach-msm/board-saga-wifi.c
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <asm/mach-types.h>
#include <asm/gpio.h>
#include <asm/io.h>
#include <linux/skbuff.h>
#ifdef CONFIG_BCM4329_PURE_ANDROID
#include <linux/wlan_plat.h>
#else
#include <linux/wifi_tiwlan.h>
#endif

#include "board-saga.h"

int saga_wifi_power(int on);
int saga_wifi_reset(int on);
int saga_wifi_set_carddetect(int on);

#define PREALLOC_WLAN_NUMBER_OF_SECTIONS 4
#define PREALLOC_WLAN_NUMBER_OF_BUFFERS 160
#define PREALLOC_WLAN_SECTION_HEADER 24

#define WLAN_SECTION_SIZE_0 (PREALLOC_WLAN_NUMBER_OF_BUFFERS * 128)
#define WLAN_SECTION_SIZE_1 (PREALLOC_WLAN_NUMBER_OF_BUFFERS * 128)
#define WLAN_SECTION_SIZE_2 (PREALLOC_WLAN_NUMBER_OF_BUFFERS * 512)
#define WLAN_SECTION_SIZE_3 (PREALLOC_WLAN_NUMBER_OF_BUFFERS * 1024)

#define WLAN_SKB_BUF_NUM 16

static struct sk_buff *wlan_static_skb[WLAN_SKB_BUF_NUM];

typedef struct wifi_mem_prealloc_struct {
void *mem_ptr;
unsigned long size;
} wifi_mem_prealloc_t;

static wifi_mem_prealloc_t wifi_mem_array[PREALLOC_WLAN_NUMBER_OF_SECTIONS] = {
{ NULL, (WLAN_SECTION_SIZE_0 + PREALLOC_WLAN_SECTION_HEADER) },
{ NULL, (WLAN_SECTION_SIZE_1 + PREALLOC_WLAN_SECTION_HEADER) },
{ NULL, (WLAN_SECTION_SIZE_2 + PREALLOC_WLAN_SECTION_HEADER) },
{ NULL, (WLAN_SECTION_SIZE_3 + PREALLOC_WLAN_SECTION_HEADER) }
};

static void *saga_wifi_mem_prealloc(int section, unsigned long size)
{
if (section == PREALLOC_WLAN_NUMBER_OF_SECTIONS)
return wlan_static_skb;
if ((section < 0) || (section > PREALLOC_WLAN_NUMBER_OF_SECTIONS))
return NULL;
if (wifi_mem_array[section].size < size)
return NULL;
return wifi_mem_array[section].mem_ptr;
}

int __init saga_init_wifi_mem(void)
{
int i;

for (i = 0 ; (i < WLAN_SKB_BUF_NUM); i++) {
if (i < (WLAN_SKB_BUF_NUM/2))
wlan_static_skb[i] = dev_alloc_skb(4096);
else
wlan_static_skb[i] = dev_alloc_skb(8192);
}
for (i = 0 ; (i < PREALLOC_WLAN_NUMBER_OF_SECTIONS); i++) {
wifi_mem_array[i].mem_ptr = kmalloc(wifi_mem_array[i].size,
GFP_KERNEL);
if (wifi_mem_array[i].mem_ptr == NULL)
return -ENOMEM;
}
return 0;
}

static struct resource saga_wifi_resources[] = {
[0] = {
.name = "bcm4329_wlan_irq",
.start = MSM_GPIO_TO_INT(SAGA_GPIO_WIFI_IRQ),
.end = MSM_GPIO_TO_INT(SAGA_GPIO_WIFI_IRQ),
#ifdef CONFIG_BCM4329_PURE_ANDROID
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL | IORESOURCE_IRQ_SHAREABLE,
#else
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWEDGE,
#endif
},
};

static struct wifi_platform_data saga_wifi_control = {
.set_power = saga_wifi_power,
.set_reset = saga_wifi_reset,
.set_carddetect = saga_wifi_set_carddetect,
.mem_prealloc = saga_wifi_mem_prealloc,
#ifndef CONFIG_BCM4329_PURE_ANDROID
.dot11n_enable = 1,
#endif
//.cscan_enable = 1,
};

static struct platform_device saga_wifi_device = {
.name = "bcm4329_wlan",
.id = 1,
.num_resources = ARRAY_SIZE(saga_wifi_resources),
.resource = saga_wifi_resources,
.dev = {
.platform_data = &saga_wifi_control,
},
};

extern unsigned char *get_wifi_nvs_ram(void);

static unsigned saga_wifi_update_nvs(char *str)
{
#define NVS_LEN_OFFSET 0x0C
#define NVS_DATA_OFFSET 0x40
unsigned char *ptr;
unsigned len;

if (!str)
return -EINVAL;
ptr = get_wifi_nvs_ram();
/* Size in format LE assumed */
memcpy(&len, ptr + NVS_LEN_OFFSET, sizeof(len));

/* the last bye in NVRAM is 0, trim it */
if (ptr[NVS_DATA_OFFSET + len - 1] == 0)
len -= 1;

if (ptr[NVS_DATA_OFFSET + len - 1] != '\n') {
len += 1;
ptr[NVS_DATA_OFFSET + len - 1] = '\n';
}

strcpy(ptr + NVS_DATA_OFFSET + len, str);
len += strlen(str);
memcpy(ptr + NVS_LEN_OFFSET, &len, sizeof(len));
return 0;
}

int __init saga_wifi_init(void)
{
int ret;

printk(KERN_INFO "%s: start\n", __func__);
saga_wifi_update_nvs("sd_oobonly=1\n");
saga_wifi_update_nvs("btc_params80=0\n");
saga_wifi_update_nvs("btc_params6=30\n");
saga_wifi_update_nvs("btc_params70=0x32\n");
saga_init_wifi_mem();
ret = platform_device_register(&saga_wifi_device);
return ret;
}

Large diffs are not rendered by default.

@@ -0,0 +1,170 @@
/* linux/arch/arm/mach-msm/board-saga.h
* Copyright (C) 2007-2009 HTC Corporation.
*
* 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 __ARCH_ARM_MACH_MSM_BOARD_SAGA_H
#define __ARCH_ARM_MACH_MSM_BOARD_SAGA_H

#include <mach/board.h>

#define MSM_LINUX_BASE1 0x04400000
#define MSM_LINUX_SIZE1 0x0BC00000
#define MSM_LINUX_BASE2 0x20000000
#define MSM_LINUX_SIZE2 0x0B300000
#define MSM_MEM_256MB_OFFSET 0x10000000

#define MSM_GPU_MEM_BASE 0x00100000
#define MSM_GPU_MEM_SIZE 0x00300000

#define MSM_RAM_CONSOLE_BASE 0x00500000
#define MSM_RAM_CONSOLE_SIZE 0x00100000

#define MSM_PMEM_ADSP_BASE 0x2B300000
#define MSM_PMEM_ADSP_SIZE 0x02300000
#define PMEM_KERNEL_EBI1_BASE 0x2D600000
#define PMEM_KERNEL_EBI1_SIZE 0x00700000

#define MSM_PMEM_CAMERA_BASE 0x2DD00000
#define MSM_PMEM_CAMERA_SIZE 0x00000000

#define MSM_PMEM_MDP_BASE 0x2DD00000
#define MSM_PMEM_MDP_SIZE 0x02000000

#define MSM_FB_BASE 0x2FD00000
#define MSM_FB_SIZE 0x00300000

#define SAGA_GPIO_WIFI_IRQ 147
#define SAGA_GPIO_WIFI_SHUTDOWN_N 39

#define SAGA_GPIO_UART2_RX 51
#define SAGA_GPIO_UART2_TX 52

#define SAGA_GPIO_KEYPAD_POWER_KEY 46


/* Macros assume PMIC GPIOs start at 0 */
#define PM8058_GPIO_PM_TO_SYS(pm_gpio) (pm_gpio + NR_GPIO_IRQS)
#define PM8058_GPIO_SYS_TO_PM(sys_gpio) (sys_gpio - NR_GPIO_IRQS)

/* Proximity */
#define SAGA_GPIO_PROXIMITY_INT_N 18

#define SAGA_GPIO_COMPASS_INT 42
#define SAGA_GPIO_GSENSOR_INT_N 180
#define SAGA_LAYOUTS_XA_XB { \
{ { 0, 1, 0}, { 1, 0, 0}, {0, 0, -1} }, \
{ { 0, -1, 0}, { 1, 0, 0}, {0, 0, -1} }, \
{ { 1, 0, 0}, { 0, -1, 0}, {0, 0, -1} }, \
{ {-1, 0, 0}, { 0, 0, -1}, {0, 1, 0} } \
}
#define SAGA_LAYOUTS_XC { \
{ { 0, 1, 0}, {-1, 0, 0}, {0, 0, 1} }, \
{ { 0, -1, 0}, { 1, 0, 0}, {0, 0, -1} }, \
{ {-1, 0, 0}, { 0, -1, 0}, {0, 0, 1} }, \
{ {-1, 0, 0}, { 0, 0, -1}, {0, 1, 0} } \
}

#define SAGA_PMIC_GPIO_INT (27)

#define SAGA_GPIO_UP_INT_N (142)

#define SAGA_GPIO_PS_HOLD (29)

#define SAGA_MDDI_RSTz (162)
#define SAGA_LCD_ID0 (124)
#define SAGA_LCD_RSTz_ID1 (126)
#define SAGA_LCD_PCLK_1 (90)
#define SAGA_LCD_DE (91)
#define SAGA_LCD_VSYNC (92)
#define SAGA_LCD_HSYNC (93)
#define SAGA_LCD_G0 (94)
#define SAGA_LCD_G1 (95)
#define SAGA_LCD_G2 (96)
#define SAGA_LCD_G3 (97)
#define SAGA_LCD_G4 (98)
#define SAGA_LCD_G5 (99)
#define SAGA_LCD_B0 (22)
#define SAGA_LCD_B1 (100)
#define SAGA_LCD_B2 (101)
#define SAGA_LCD_B3 (102)
#define SAGA_LCD_B4 (103)
#define SAGA_LCD_B5 (104)
#define SAGA_LCD_R0 (25)
#define SAGA_LCD_R1 (105)
#define SAGA_LCD_R2 (106)
#define SAGA_LCD_R3 (107)
#define SAGA_LCD_R4 (108)
#define SAGA_LCD_R5 (109)

#define SAGA_LCD_SPI_CSz (87)

/* Audio */
#define SAGA_AUD_SPI_CSz (89)
#define SAGA_AUD_MICPATH_SEL_XA (121)

/* Flashlight */
#define SAGA_GPIO_FLASHLIGHT_FLASH 128
#define SAGA_GPIO_FLASHLIGHT_TORCH 129

/* BT */
#define SAGA_GPIO_BT_UART1_RTS (134)
#define SAGA_GPIO_BT_UART1_CTS (135)
#define SAGA_GPIO_BT_UART1_RX (136)
#define SAGA_GPIO_BT_UART1_TX (137)
#define SAGA_GPIO_BT_PCM_OUT (138)
#define SAGA_GPIO_BT_PCM_IN (139)
#define SAGA_GPIO_BT_PCM_SYNC (140)
#define SAGA_GPIO_BT_PCM_CLK (141)
#define SAGA_GPIO_BT_RESET_N (41)
#define SAGA_GPIO_BT_HOST_WAKE (26)
#define SAGA_GPIO_BT_CHIP_WAKE (50)
#define SAGA_GPIO_BT_SHUTDOWN_N (38)

#define SAGA_GPIO_USB_ID_PIN (145)

#define SAGA_VCM_PD (34)
#define SAGA_CAM1_PD (31)
#define SAGA_CLK_SEL (23) /* camera select pin */
#define SAGA_CAM2_PD (24)
#define SAGA_CAM2_RSTz (21)

#define SAGA_CODEC_3V_EN (36)
#define SAGA_GPIO_TP_ATT_N (20)

/* PMIC 8058 GPIO */
#define PMGPIO(x) (x-1)
#define SAGA_AUD_MICPATH_SEL_XB PMGPIO(10)
#define SAGA_AUD_EP_EN PMGPIO(13)
#define SAGA_VOL_UP PMGPIO(14)
#define SAGA_VOL_DN PMGPIO(15)
#define SAGA_GPIO_CHG_INT PMGPIO(16)
#define SAGA_AUD_HP_DETz PMGPIO(17)
#define SAGA_AUD_SPK_EN PMGPIO(18)
#define SAGA_AUD_HP_EN PMGPIO(19)
#define SAGA_PS_SHDN PMGPIO(20)
#define SAGA_TP_RSTz PMGPIO(21)
#define SAGA_LED_3V3_EN PMGPIO(22)
#define SAGA_SDMC_CD_N PMGPIO(23)
#define SAGA_GREEN_LED PMGPIO(24)
#define SAGA_AMBER_LED PMGPIO(25)
#define SAGA_AUD_A3254_RSTz PMGPIO(36)
#define SAGA_WIFI_SLOW_CLK PMGPIO(38)
#define SAGA_SLEEP_CLK2 PMGPIO(39)

unsigned int saga_get_engineerid(void);
int saga_init_mmc(unsigned int sys_rev);
void __init saga_audio_init(void);
int saga_init_keypad(void);
int __init saga_wifi_init(void);
int __init saga_init_panel(void);
int __init saga_rfkill_init(void);
#endif /* __ARCH_ARM_MACH_MSM_BOARD_SAGA_H */
@@ -85,6 +85,7 @@
/*for PS command 03h*/
#define CM3628_PS_MS (1 << 4)
#define CM3628_PS_HYS (1 << 0)
#define CM3628_PS_SMART_PERS (1 << 1)
#define CM3628_IT_4X_ES (1 << 6)/*for integration time*/
#define CM3628_IT_4X_MP (1 << 7)/*for integration time*/

@@ -120,6 +121,11 @@ struct cm3628_platform_data {
uint8_t enable_polling_ignore;
uint8_t ps_thd_no_cal;
uint8_t ps_thd_with_cal;
uint8_t is_cmd;
uint8_t ps_adc_offset;
uint8_t ps_adc_offset2;
uint8_t ps_debounce;
uint16_t ps_delay_time;
};

#endif