mirror of
https://github.com/AetherDroid/android_kernel_samsung_on5xelte.git
synced 2025-09-08 09:08:05 -04:00
Fixed MTP to work with TWRP
This commit is contained in:
commit
f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions
516
drivers/battery/bq24260_charger.c
Normal file
516
drivers/battery/bq24260_charger.c
Normal file
|
@ -0,0 +1,516 @@
|
|||
/*
|
||||
* bq24260_charger.c
|
||||
* Samsung bq24260 Charger Driver
|
||||
*
|
||||
* Copyright (C) 2012 Samsung Electronics
|
||||
*
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
#define DEBUG
|
||||
|
||||
#include <linux/battery/sec_charger.h>
|
||||
|
||||
static int bq24260_i2c_write(struct i2c_client *client,
|
||||
int reg, u8 *buf)
|
||||
{
|
||||
int ret;
|
||||
ret = i2c_smbus_write_i2c_block_data(client, reg, 1, buf);
|
||||
if (ret < 0)
|
||||
dev_err(&client->dev, "%s: Error(%d)\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int bq24260_i2c_read(struct i2c_client *client,
|
||||
int reg, u8 *buf)
|
||||
{
|
||||
int ret;
|
||||
ret = i2c_smbus_read_i2c_block_data(client, reg, 1, buf);
|
||||
if (ret < 0)
|
||||
dev_err(&client->dev, "%s: Error(%d)\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void bq24260_i2c_write_array(struct i2c_client *client,
|
||||
u8 *buf, int size)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < size; i += 3)
|
||||
bq24260_i2c_write(client, (u8) (*(buf + i)), (buf + i) + 1);
|
||||
}
|
||||
|
||||
static void bq24260_set_command(struct i2c_client *client,
|
||||
int reg, int datum)
|
||||
{
|
||||
int val;
|
||||
u8 data = 0;
|
||||
val = bq24260_i2c_read(client, reg, &data);
|
||||
if (val >= 0) {
|
||||
dev_dbg(&client->dev, "%s : reg(0x%02x): 0x%02x(0x%02x)",
|
||||
__func__, reg, data, datum);
|
||||
if (data != datum) {
|
||||
data = datum;
|
||||
if (bq24260_i2c_write(client, reg, &data) < 0)
|
||||
dev_err(&client->dev,
|
||||
"%s : error!\n", __func__);
|
||||
val = bq24260_i2c_read(client, reg, &data);
|
||||
if (val >= 0)
|
||||
dev_dbg(&client->dev, " => 0x%02x\n", data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void bq24260_test_read(struct i2c_client *client)
|
||||
{
|
||||
u8 data = 0;
|
||||
u32 addr = 0;
|
||||
for (addr = 0; addr <= 0x06; addr++) {
|
||||
bq24260_i2c_read(client, addr, &data);
|
||||
dev_dbg(&client->dev,
|
||||
"bq24260 addr : 0x%02x data : 0x%02x\n", addr, data);
|
||||
}
|
||||
}
|
||||
|
||||
static void bq24260_read_regs(struct i2c_client *client, char *str)
|
||||
{
|
||||
u8 data = 0;
|
||||
u32 addr = 0;
|
||||
|
||||
for (addr = 0; addr <= 0x06; addr++) {
|
||||
bq24260_i2c_read(client, addr, &data);
|
||||
sprintf(str+strlen(str), "0x%x, ", data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int bq24260_get_charging_status(struct i2c_client *client)
|
||||
{
|
||||
int status = POWER_SUPPLY_STATUS_UNKNOWN;
|
||||
u8 data = 0;
|
||||
|
||||
bq24260_i2c_read(client, BQ24260_STATUS, &data);
|
||||
dev_info(&client->dev,
|
||||
"%s : charger status(0x%02x)\n", __func__, data);
|
||||
|
||||
data = (data & 0x30);
|
||||
|
||||
switch (data) {
|
||||
case 0x00:
|
||||
status = POWER_SUPPLY_STATUS_DISCHARGING;
|
||||
break;
|
||||
case 0x10:
|
||||
status = POWER_SUPPLY_STATUS_CHARGING;
|
||||
break;
|
||||
case 0x20:
|
||||
status = POWER_SUPPLY_STATUS_FULL;
|
||||
break;
|
||||
case 0x30:
|
||||
status = POWER_SUPPLY_STATUS_NOT_CHARGING;
|
||||
break;
|
||||
}
|
||||
|
||||
return (int)status;
|
||||
}
|
||||
|
||||
static int bq24260_get_charging_health(struct i2c_client *client)
|
||||
{
|
||||
int health = POWER_SUPPLY_HEALTH_GOOD;
|
||||
u8 data = 0;
|
||||
|
||||
bq24260_i2c_read(client, BQ24260_STATUS, &data);
|
||||
dev_info(&client->dev,
|
||||
"%s : charger status(0x%02x)\n", __func__, data);
|
||||
|
||||
if ((data & 0x30) == 0x30) { /* check for fault */
|
||||
data = (data & 0x07);
|
||||
|
||||
switch (data) {
|
||||
case 0x01:
|
||||
health = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
|
||||
break;
|
||||
case 0x02:
|
||||
health = POWER_SUPPLY_HEALTH_UNDERVOLTAGE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (int)health;
|
||||
}
|
||||
|
||||
static u8 bq24260_get_float_voltage_data(
|
||||
int float_voltage)
|
||||
{
|
||||
u8 data;
|
||||
|
||||
if (float_voltage < 3500)
|
||||
float_voltage = 3500;
|
||||
|
||||
data = (float_voltage - 3500) / 20;
|
||||
|
||||
return data << 2;
|
||||
}
|
||||
|
||||
static u8 bq24260_get_input_current_limit_data(
|
||||
int input_current)
|
||||
{
|
||||
u8 data = 0x00;
|
||||
|
||||
if (input_current <= 100)
|
||||
data = 0x00;
|
||||
else if (input_current <= 150)
|
||||
data = 0x01;
|
||||
else if (input_current <= 500)
|
||||
data = 0x02;
|
||||
else if (input_current <= 900)
|
||||
data = 0x03;
|
||||
else if (input_current <= 1000)
|
||||
data = 0x04;
|
||||
else if (input_current <= 2000)/* will be set as 1950mA */
|
||||
data = 0x06;
|
||||
else /* No limit */
|
||||
data = 0x07;
|
||||
|
||||
return data << 4;
|
||||
}
|
||||
|
||||
static u8 bq24260_get_termination_current_limit_data(
|
||||
int termination_current)
|
||||
{
|
||||
u8 data;
|
||||
|
||||
/* default offset 50mA, max 300mA */
|
||||
data = (termination_current - 50) / 50;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static u8 bq24260_get_fast_charging_current_data(
|
||||
int fast_charging_current)
|
||||
{
|
||||
u8 data;
|
||||
|
||||
/* default offset 500mA */
|
||||
if (fast_charging_current < 500)
|
||||
fast_charging_current = 500;
|
||||
|
||||
data = (fast_charging_current - 500) / 100;
|
||||
|
||||
return data << 3;
|
||||
}
|
||||
|
||||
static void bq24260_charger_function_conrol(
|
||||
struct i2c_client *client)
|
||||
{
|
||||
struct sec_charger_info *charger = i2c_get_clientdata(client);
|
||||
union power_supply_propval val;
|
||||
int full_check_type;
|
||||
u8 data;
|
||||
if (charger->charging_current < 0) {
|
||||
dev_dbg(&client->dev,
|
||||
"%s : OTG is activated. Ignore command!\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (charger->cable_type ==
|
||||
POWER_SUPPLY_TYPE_BATTERY) {
|
||||
data = 0x00;
|
||||
bq24260_i2c_read(client, BQ24260_CONTROL, &data);
|
||||
data |= 0x2;
|
||||
data &= 0x7f; /* Prevent register reset */
|
||||
bq24260_set_command(client,
|
||||
BQ24260_CONTROL, data);
|
||||
} else {
|
||||
data = 0x00;
|
||||
bq24260_i2c_read(client, BQ24260_CONTROL, &data);
|
||||
/* Enable charging */
|
||||
data &= 0x7d; /*default enabled*/
|
||||
psy_do_property("battery", get,
|
||||
POWER_SUPPLY_PROP_CHARGE_NOW, val);
|
||||
if (val.intval == SEC_BATTERY_CHARGING_1ST)
|
||||
full_check_type = charger->pdata->full_check_type;
|
||||
else
|
||||
full_check_type = charger->pdata->full_check_type_2nd;
|
||||
/* Termination setting */
|
||||
switch (full_check_type) {
|
||||
case SEC_BATTERY_FULLCHARGED_CHGGPIO:
|
||||
case SEC_BATTERY_FULLCHARGED_CHGINT:
|
||||
case SEC_BATTERY_FULLCHARGED_CHGPSY:
|
||||
/* Enable Current Termination */
|
||||
data |= 0x04;
|
||||
break;
|
||||
default:
|
||||
data &= 0x7b;
|
||||
break;
|
||||
}
|
||||
/* Input current limit */
|
||||
dev_dbg(&client->dev, "%s : input current (%dmA)\n",
|
||||
__func__, charger->pdata->charging_current
|
||||
[charger->cable_type].input_current_limit);
|
||||
data &= 0x0F;
|
||||
data |= bq24260_get_input_current_limit_data(
|
||||
charger->pdata->charging_current
|
||||
[charger->cable_type].input_current_limit);
|
||||
bq24260_set_command(client,
|
||||
BQ24260_CONTROL, data);
|
||||
|
||||
data = 0x00;
|
||||
/* Float voltage */
|
||||
dev_dbg(&client->dev, "%s : float voltage (%dmV)\n",
|
||||
__func__, charger->pdata->chg_float_voltage);
|
||||
data |= bq24260_get_float_voltage_data(
|
||||
charger->pdata->chg_float_voltage);
|
||||
bq24260_set_command(client,
|
||||
BQ24260_VOLTAGE, data);
|
||||
|
||||
data = 0x00;
|
||||
/* Fast charge and Termination current */
|
||||
dev_dbg(&client->dev, "%s : fast charging current (%dmA)\n",
|
||||
__func__, charger->charging_current);
|
||||
data |= bq24260_get_fast_charging_current_data(
|
||||
charger->charging_current);
|
||||
dev_dbg(&client->dev, "%s : termination current (%dmA)\n",
|
||||
__func__, charger->pdata->charging_current[
|
||||
charger->cable_type].full_check_current_1st >= 300 ?
|
||||
300 : charger->pdata->charging_current[
|
||||
charger->cable_type].full_check_current_1st);
|
||||
data |= bq24260_get_termination_current_limit_data(
|
||||
charger->pdata->charging_current[
|
||||
charger->cable_type].full_check_current_1st);
|
||||
bq24260_set_command(client,
|
||||
BQ24260_CURRENT, data);
|
||||
|
||||
/* Special Charger Voltage
|
||||
* Normal charge current
|
||||
*/
|
||||
bq24260_i2c_read(client, BQ24260_SPECIAL, &data);
|
||||
data &= 0xdf;
|
||||
bq24260_set_command(client,
|
||||
BQ24260_SPECIAL, data);
|
||||
}
|
||||
}
|
||||
|
||||
static void bq24260_charger_otg_conrol(
|
||||
struct i2c_client *client)
|
||||
{
|
||||
struct sec_charger_info *charger = i2c_get_clientdata(client);
|
||||
u8 data;
|
||||
if (charger->cable_type ==
|
||||
POWER_SUPPLY_TYPE_BATTERY) {
|
||||
dev_info(&client->dev, "%s : turn off OTG\n", __func__);
|
||||
/* turn off OTG */
|
||||
bq24260_i2c_read(client, BQ24260_STATUS, &data);
|
||||
data &= 0xbf;
|
||||
bq24260_set_command(client,
|
||||
BQ24260_STATUS, data);
|
||||
} else {
|
||||
dev_info(&client->dev, "%s : turn on OTG\n", __func__);
|
||||
/* turn on OTG */
|
||||
bq24260_i2c_read(client, BQ24260_STATUS, &data);
|
||||
data |= 0x40;
|
||||
bq24260_set_command(client,
|
||||
BQ24260_STATUS, data);
|
||||
}
|
||||
}
|
||||
|
||||
static int bq24260_get_charge_type(struct i2c_client *client)
|
||||
{
|
||||
int ret;
|
||||
u8 data;
|
||||
|
||||
bq24260_i2c_read(client, BQ24260_STATUS, &data);
|
||||
data = (data & 0x30)>>4;
|
||||
|
||||
switch (data) {
|
||||
case 0x01:
|
||||
ret = POWER_SUPPLY_CHARGE_TYPE_FAST;
|
||||
break;
|
||||
default:
|
||||
ret = POWER_SUPPLY_CHARGE_TYPE_NONE;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool sec_hal_chg_init(struct i2c_client *client)
|
||||
{
|
||||
bq24260_test_read(client);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool sec_hal_chg_suspend(struct i2c_client *client)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool sec_hal_chg_resume(struct i2c_client *client)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool sec_hal_chg_get_property(struct i2c_client *client,
|
||||
enum power_supply_property psp,
|
||||
union power_supply_propval *val)
|
||||
{
|
||||
struct sec_charger_info *charger = i2c_get_clientdata(client);
|
||||
u8 data;
|
||||
|
||||
switch (psp) {
|
||||
case POWER_SUPPLY_PROP_STATUS:
|
||||
val->intval = bq24260_get_charging_status(client);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CHARGE_TYPE:
|
||||
val->intval = bq24260_get_charge_type(client);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_HEALTH:
|
||||
val->intval = bq24260_get_charging_health(client);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CURRENT_NOW:
|
||||
if (charger->charging_current) {
|
||||
/* Rsns 0.068 Ohm */
|
||||
bq24260_i2c_read(client, BQ24260_CURRENT, &data);
|
||||
val->intval = (data >> 3) * 100 + 500;
|
||||
} else
|
||||
val->intval = 0;
|
||||
dev_dbg(&client->dev,
|
||||
"%s : set-current(%dmA), current now(%dmA)\n",
|
||||
__func__, charger->charging_current, val->intval);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool sec_hal_chg_set_property(struct i2c_client *client,
|
||||
enum power_supply_property psp,
|
||||
const union power_supply_propval *val)
|
||||
{
|
||||
struct sec_charger_info *charger = i2c_get_clientdata(client);
|
||||
|
||||
switch (psp) {
|
||||
/* val->intval : type */
|
||||
case POWER_SUPPLY_PROP_ONLINE:
|
||||
if (charger->pdata->chg_gpio_en) {
|
||||
if (gpio_request(charger->pdata->chg_gpio_en,
|
||||
"CHG_EN") < 0) {
|
||||
dev_err(&client->dev,
|
||||
"failed to request vbus_in gpio\n");
|
||||
break;
|
||||
}
|
||||
if (charger->cable_type ==
|
||||
POWER_SUPPLY_TYPE_BATTERY)
|
||||
gpio_set_value_cansleep(
|
||||
charger->pdata->chg_gpio_en,
|
||||
charger->pdata->chg_polarity_en ?
|
||||
0 : 1);
|
||||
else
|
||||
gpio_set_value_cansleep(
|
||||
charger->pdata->chg_gpio_en,
|
||||
charger->pdata->chg_polarity_en ?
|
||||
1 : 0);
|
||||
gpio_free(charger->pdata->chg_gpio_en);
|
||||
}
|
||||
/* val->intval : charging current */
|
||||
case POWER_SUPPLY_PROP_CURRENT_NOW:
|
||||
if (charger->charging_current < 0)
|
||||
bq24260_charger_otg_conrol(client);
|
||||
else if (charger->charging_current > 0)
|
||||
bq24260_charger_function_conrol(client);
|
||||
else {
|
||||
bq24260_charger_function_conrol(client);
|
||||
bq24260_charger_otg_conrol(client);
|
||||
}
|
||||
bq24260_test_read(client);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
ssize_t sec_hal_chg_show_attrs(struct device *dev,
|
||||
const ptrdiff_t offset, char *buf)
|
||||
{
|
||||
struct power_supply *psy = dev_get_drvdata(dev);
|
||||
struct sec_charger_info *chg =
|
||||
container_of(psy, struct sec_charger_info, psy_chg);
|
||||
int i = 0;
|
||||
char *str = NULL;
|
||||
|
||||
switch (offset) {
|
||||
case CHG_REG:
|
||||
i += scnprintf(buf + i, PAGE_SIZE - i, "%x\n",
|
||||
chg->reg_addr);
|
||||
break;
|
||||
case CHG_DATA:
|
||||
i += scnprintf(buf + i, PAGE_SIZE - i, "%x\n",
|
||||
chg->reg_data);
|
||||
break;
|
||||
case CHG_REGS:
|
||||
str = kzalloc(sizeof(char)*1024, GFP_KERNEL);
|
||||
if (!str)
|
||||
return -ENOMEM;
|
||||
|
||||
bq24260_read_regs(chg->client, str);
|
||||
i += scnprintf(buf + i, PAGE_SIZE - i, "%s\n",
|
||||
str);
|
||||
|
||||
kfree(str);
|
||||
break;
|
||||
default:
|
||||
i = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
ssize_t sec_hal_chg_store_attrs(struct device *dev,
|
||||
const ptrdiff_t offset,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct power_supply *psy = dev_get_drvdata(dev);
|
||||
struct sec_charger_info *chg =
|
||||
container_of(psy, struct sec_charger_info, psy_chg);
|
||||
int ret = 0;
|
||||
int x = 0;
|
||||
u8 data = 0;
|
||||
|
||||
switch (offset) {
|
||||
case CHG_REG:
|
||||
if (sscanf(buf, "%x\n", &x) == 1) {
|
||||
chg->reg_addr = x;
|
||||
bq24260_i2c_read(chg->client,
|
||||
chg->reg_addr, &data);
|
||||
chg->reg_data = data;
|
||||
dev_dbg(dev, "%s: (read) addr = 0x%x, data = 0x%x\n",
|
||||
__func__, chg->reg_addr, chg->reg_data);
|
||||
ret = count;
|
||||
}
|
||||
break;
|
||||
case CHG_DATA:
|
||||
if (sscanf(buf, "%x\n", &x) == 1) {
|
||||
data = (u8)x;
|
||||
dev_dbg(dev, "%s: (write) addr = 0x%x, data = 0x%x\n",
|
||||
__func__, chg->reg_addr, data);
|
||||
bq24260_i2c_write(chg->client,
|
||||
chg->reg_addr, &data);
|
||||
ret = count;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue