185 lines
4.1 KiB
C
185 lines
4.1 KiB
C
|
/* driver/i2c/chip/tap6130.c
|
||
|
*
|
||
|
* TI TPA6130 Headset Amp
|
||
|
*
|
||
|
* 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.
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
#include <linux/i2c.h>
|
||
|
#include <linux/miscdevice.h>
|
||
|
#include <asm/gpio.h>
|
||
|
#include <asm/uaccess.h>
|
||
|
#include <linux/delay.h>
|
||
|
#include <linux/freezer.h>
|
||
|
#include <mach/tpa6130.h>
|
||
|
#include <linux/mutex.h>
|
||
|
#include <mach/msm_rpcrouter.h>
|
||
|
|
||
|
#define HEADSET_MTOA_PROG 0x30100003
|
||
|
#define HEADSET_MTOA_VERS 0
|
||
|
#define HTC_HEADSET_NULL_PROC 0
|
||
|
#define HTC_HEADSET_CTL_PROC 1
|
||
|
|
||
|
static struct i2c_client *this_client;
|
||
|
struct mutex amp_mutex;
|
||
|
static struct tpa6130_platform_data *pdata;
|
||
|
|
||
|
static int i2c_on;
|
||
|
char buffer[2];
|
||
|
|
||
|
static int I2C_TxData(char *txData, int length)
|
||
|
{
|
||
|
struct i2c_msg msg[] = {
|
||
|
{
|
||
|
.addr = this_client->addr,
|
||
|
.flags = 0,
|
||
|
.len = length,
|
||
|
.buf = txData,
|
||
|
},
|
||
|
};
|
||
|
|
||
|
if (i2c_transfer(this_client->adapter, msg, 1) < 0) {
|
||
|
pr_err("tpa6130 :I2C transfer error\n");
|
||
|
return -EIO;
|
||
|
} else
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void set_headset_amp(int on)
|
||
|
{
|
||
|
mutex_lock(&_mutex);
|
||
|
if (on && !i2c_on) {
|
||
|
buffer[0] = 0x01;
|
||
|
buffer[1] = 0xC0;
|
||
|
buffer[2] = 0x3E;
|
||
|
if (I2C_TxData(buffer, 3) == 0) {
|
||
|
i2c_on = 1;
|
||
|
pr_err("tpa6130: turn on headset amp !\n");
|
||
|
}
|
||
|
} else if (!on && i2c_on) {
|
||
|
buffer[0] = 0x01;
|
||
|
buffer[1] = 0xC1;
|
||
|
if (I2C_TxData(buffer, 2) == 0) {
|
||
|
i2c_on = 0;
|
||
|
pr_err("tpa6130: turn off headset amp !\n");
|
||
|
}
|
||
|
}
|
||
|
mutex_unlock(&_mutex);
|
||
|
}
|
||
|
|
||
|
static int handle_headset_call(struct msm_rpc_server *server,
|
||
|
struct rpc_request_hdr *req, unsigned len)
|
||
|
{
|
||
|
if (!pdata->enable_rpc_server)
|
||
|
return 0;
|
||
|
|
||
|
struct rpc_headset_amp_ctl_args *args;
|
||
|
switch (req->procedure) {
|
||
|
case HTC_HEADSET_NULL_PROC:
|
||
|
return 0;
|
||
|
case HTC_HEADSET_CTL_PROC:
|
||
|
args = (struct rpc_headset_amp_ctl_args *)(req + 1);
|
||
|
args->on = be32_to_cpu(args->on);
|
||
|
if (args->on) {
|
||
|
gpio_set_value(pdata->gpio_hp_sd, 1);
|
||
|
msleep(10);
|
||
|
set_headset_amp(args->on);
|
||
|
} else if (!args->on) {
|
||
|
set_headset_amp(args->on);
|
||
|
gpio_set_value(pdata->gpio_hp_sd, 0);
|
||
|
}
|
||
|
return 0;
|
||
|
default:
|
||
|
pr_err("tpa6130a: the wrong proc for headset server\n");
|
||
|
}
|
||
|
return -ENODEV;
|
||
|
}
|
||
|
|
||
|
static struct msm_rpc_server headset_server = {
|
||
|
.prog = HEADSET_MTOA_PROG,
|
||
|
.vers = HEADSET_MTOA_VERS,
|
||
|
.rpc_call = handle_headset_call
|
||
|
};
|
||
|
|
||
|
int tpa6130_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
||
|
{
|
||
|
int ret = 0;
|
||
|
|
||
|
pdata = client->dev.platform_data;
|
||
|
if (pdata == NULL) {
|
||
|
pr_err("tpa6130: platform data is NULL\n");
|
||
|
goto fault;
|
||
|
}
|
||
|
|
||
|
if (pdata->enable_rpc_server) {
|
||
|
msm_rpc_create_server(&headset_server);
|
||
|
|
||
|
ret = gpio_request(pdata->gpio_hp_sd, "tpa6130");
|
||
|
if (ret < 0) {
|
||
|
pr_err("tap6130a : gpio request failed\n");
|
||
|
goto fault;
|
||
|
}
|
||
|
|
||
|
ret = gpio_direction_output(pdata->gpio_hp_sd, 1);
|
||
|
if (ret < 0) {
|
||
|
pr_err("tap6130a: request reset gpio failed\n");
|
||
|
goto fault;
|
||
|
}
|
||
|
gpio_set_value(pdata->gpio_hp_sd, 0);
|
||
|
}
|
||
|
|
||
|
this_client = client;
|
||
|
|
||
|
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
|
||
|
pr_err("tpa6130a: i2c check functionality error\n");
|
||
|
goto fault;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
fault:
|
||
|
return -ENODEV;
|
||
|
}
|
||
|
|
||
|
static int tpa6130_remove(struct i2c_client *client)
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
static const struct i2c_device_id tpa6130_id[] = {
|
||
|
{ TPA6130_I2C_NAME, 0 },
|
||
|
{ }
|
||
|
};
|
||
|
|
||
|
static struct i2c_driver tpa6130_driver = {
|
||
|
.probe = tpa6130_probe,
|
||
|
.remove = tpa6130_remove,
|
||
|
.id_table = tpa6130_id,
|
||
|
.driver = {
|
||
|
.name = TPA6130_I2C_NAME,
|
||
|
},
|
||
|
};
|
||
|
|
||
|
static int __init tpa6130_init(void)
|
||
|
{
|
||
|
pr_err("tpa6130 HP AMP: init\n");
|
||
|
mutex_init(&_mutex);
|
||
|
return i2c_add_driver(&tpa6130_driver);
|
||
|
}
|
||
|
|
||
|
static void __exit tpa6130_exit(void)
|
||
|
{
|
||
|
i2c_del_driver(&tpa6130_driver);
|
||
|
}
|
||
|
|
||
|
module_init(tpa6130_init);
|
||
|
module_exit(tpa6130_exit);
|