blob: f818aad0c8053a076acd89643e134507cf51836d [file] [log] [blame] [edit]
/* 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/kernel.h>
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/mpu.h>
#include <linux/gp2a.h>
#include <linux/i2c/twl6030-madc.h>
#include "mux.h"
#include "board-tuna.h"
#define GPIO_GYRO_INT 45
#define GPIO_ACC_INT 122
#define GPIO_MAG_INT 176
#define GPIO_PS_ON 25
#define GPIO_PS_VOUT 21
#define GPIO_MSENSE_IRQ 157
#define GP2A_LIGHT_ADC_CHANNEL 4
static int gp2a_light_adc_value(void)
{
return twl6030_get_madc_conversion(GP2A_LIGHT_ADC_CHANNEL);
}
static void gp2a_power(bool on)
{
/* this controls the power supply rail to the gp2a IC */
gpio_set_value(GPIO_PS_ON, on);
}
static void gp2a_gpio_init(void)
{
int ret = gpio_request(GPIO_PS_ON, "gp2a_power_supply_on");
if (ret) {
pr_err("%s Failed to request gpio gp2a power supply\n",
__func__);
return;
}
/* set power pin to output, initially powered off*/
ret = gpio_direction_output(GPIO_PS_ON, 0);
if (ret) {
pr_err("%s Failed in gpio_direction_output, value 0 with error %d\n",
__func__, ret);
}
}
static s8 orientation_back[] = {
-1, 0, 0,
0, 1, 0,
0, 0, -1,
};
static s8 orientation_back_right_90[] = {
0, -1, 0,
-1, 0, 0,
0, 0, -1,
};
static s8 orientation_back_left_90[] = {
0, 1, 0,
1, 0, 0,
0, 0, -1,
};
static s8 orientation_back_180[] = {
1, 0, 0,
0, -1, 0,
0, 0, -1,
};
/*
* A correction matrix for YAS530
* which takes care of soft iron effect in TORO
*/
static s32 compass_correction_matrix_toro[] = {
1072, -51, -22,
-30, 910, -4,
-23, -63, 1024,
};
static void rotcpy(s8 dst[3 * 3], const s8 src[3 * 3])
{
memcpy(dst, src, 3 * 3);
}
static struct mpu_platform_data mpu_data = {
.int_config = 0x10,
.orientation = { 1, 0, 0,
0, 1, 0,
0, 0, 1 },
/* accel */
.accel = {
.irq = OMAP_GPIO_IRQ(GPIO_ACC_INT),
.adapt_num = 4,
.bus = EXT_SLAVE_BUS_SECONDARY,
.address = 0x18,
.orientation = { 1, 0, 0,
0, 1, 0,
0, 0, 1 },
},
/* compass */
.compass = {
.irq = OMAP_GPIO_IRQ(GPIO_MAG_INT),
.adapt_num = 4,
.bus = EXT_SLAVE_BUS_PRIMARY,
.address = 0x2E,
.orientation = { 1, 0, 0,
0, 1, 0,
0, 0, 1 },
},
};
static struct gp2a_platform_data gp2a_pdata = {
.power = gp2a_power,
.p_out = GPIO_PS_VOUT,
.light_adc_value = gp2a_light_adc_value,
};
static struct i2c_board_info __initdata tuna_sensors_i2c4_boardinfo[] = {
{
I2C_BOARD_INFO("mpu3050", 0x68),
.irq = OMAP_GPIO_IRQ(GPIO_GYRO_INT),
.platform_data = &mpu_data,
},
{
I2C_BOARD_INFO("bma250", 0x18),
.irq = OMAP_GPIO_IRQ(GPIO_ACC_INT),
.platform_data = &mpu_data.accel,
},
{
I2C_BOARD_INFO("yas530", 0x2e),
.irq = OMAP_GPIO_IRQ(GPIO_MAG_INT),
.platform_data = &mpu_data.compass,
},
{
I2C_BOARD_INFO("gp2a", 0x44),
.platform_data = &gp2a_pdata,
},
{
I2C_BOARD_INFO("bmp180", 0x77),
},
};
static void omap4_tuna_fixup_orientations_maguro(int revision)
{
if (revision >= 3) {
rotcpy(mpu_data.orientation, orientation_back_right_90);
rotcpy(mpu_data.accel.orientation, orientation_back_left_90);
} else if (revision >= 2) {
rotcpy(mpu_data.orientation, orientation_back_right_90);
rotcpy(mpu_data.accel.orientation, orientation_back_180);
} else if (revision == 1) {
rotcpy(mpu_data.accel.orientation, orientation_back_left_90);
}
}
static void omap4_tuna_fixup_orientations_toro(int revision)
{
if (revision >= 2) {
rotcpy(mpu_data.orientation, orientation_back_left_90);
rotcpy(mpu_data.accel.orientation, orientation_back);
rotcpy(mpu_data.compass.orientation, orientation_back_180);
} else if (revision >= 1) {
rotcpy(mpu_data.orientation, orientation_back_left_90);
rotcpy(mpu_data.accel.orientation, orientation_back_180);
rotcpy(mpu_data.compass.orientation, orientation_back_left_90);
}
}
void __init omap4_tuna_sensors_init(void)
{
omap_mux_init_gpio(GPIO_GYRO_INT, OMAP_PIN_INPUT);
omap_mux_init_gpio(GPIO_ACC_INT, OMAP_PIN_INPUT);
omap_mux_init_gpio(GPIO_MAG_INT, OMAP_PIN_INPUT);
omap_mux_init_gpio(GPIO_PS_ON, OMAP_PIN_OUTPUT);
omap_mux_init_gpio(GPIO_PS_VOUT, OMAP_WAKEUP_EN | OMAP_PIN_INPUT);
gpio_request(GPIO_GYRO_INT, "GYRO_INT");
gpio_direction_input(GPIO_GYRO_INT);
gpio_request(GPIO_ACC_INT, "ACC_INT");
gpio_direction_input(GPIO_ACC_INT);
gpio_request(GPIO_MAG_INT, "MAG_INT");
gpio_direction_input(GPIO_MAG_INT);
gpio_request(GPIO_MSENSE_IRQ, "MSENSE_IRQ");
gpio_direction_output(GPIO_MSENSE_IRQ, 1);
/* optical sensor */
gp2a_gpio_init();
if (omap4_tuna_get_type() == TUNA_TYPE_MAGURO) {
omap4_tuna_fixup_orientations_maguro(omap4_tuna_get_revision());
} else if (omap4_tuna_get_type() == TUNA_TYPE_TORO) {
omap4_tuna_fixup_orientations_toro(omap4_tuna_get_revision());
mpu_data.compass.private_data = compass_correction_matrix_toro;
}
i2c_register_board_info(4, tuna_sensors_i2c4_boardinfo,
ARRAY_SIZE(tuna_sensors_i2c4_boardinfo));
}