pull in max8903b_charger

This commit is contained in:
James Sullins
2012-01-03 01:51:29 -06:00
parent 2a285a6144
commit e8075b6013
4 changed files with 439 additions and 0 deletions

View File

@@ -219,6 +219,12 @@ config CHARGER_MAX8903
pins based on the status of charger connections with interrupt
handlers.
config CHARGER_MAX8903B
tristate "MAXIM 8903B Charger (HP/Palm)"
default n
help
Say Y to enable support for the MAX8903B charger.
config CHARGER_TWL4030
tristate "OMAP TWL4030 BCI charger driver"
depends on TWL4030_CORE
@@ -352,4 +358,6 @@ config PM8921_BMS
help
Say Y here to enable support for pm8921 chip bms subdevice
endif # POWER_SUPPLY

View File

@@ -34,6 +34,7 @@ obj-$(CONFIG_BATTERY_JZ4740) += jz4740-battery.o
obj-$(CONFIG_BATTERY_INTEL_MID) += intel_mid_battery.o
obj-$(CONFIG_CHARGER_ISP1704) += isp1704_charger.o
obj-$(CONFIG_CHARGER_MAX8903) += max8903_charger.o
obj-$(CONFIG_CHARGER_MAX8903B) += max8903b_charger.o
obj-$(CONFIG_CHARGER_TWL4030) += twl4030_charger.o
obj-$(CONFIG_CHARGER_GPIO) += gpio-charger.o
obj-$(CONFIG_BATTERY_MSM) += msm_battery.o

View File

@@ -0,0 +1,392 @@
/*
* Copyright (c) 2010, Hewlett-Packard Co. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
*/
#include <linux/bitmap.h>
#include <linux/bitops.h>
#include <linux/gpio.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/spinlock.h>
#include <linux/pm_runtime.h>
#include <mach/msm_iomap.h>
#include <linux/kernel.h>
#include <linux/power_supply.h>
#include <linux/sysfs.h>
#include <linux/max8903b_charger.h>
static struct max8903b_platform_data *pdevice_resource;
static enum max8903b_current current_limit;
static int max8903b_current_setup(enum max8903b_current value)
{
int rc = 0;
enum max8903b_current old_current_limit = current_limit;
current_limit = value;
switch (value) {
case CHARGE_DISABLE:
/* disable charging */
gpio_set_value(pdevice_resource->CEN_N_in, pdevice_resource->CEN_N_in_polarity ? 0 : 1); /* charger disable */
printk(KERN_INFO "%s: ### CHARGE_DISABLE\n", __func__);
break;
case CURRENT_ZERO: // this is for no charger connection.
gpio_set_value(pdevice_resource->DCM_in, pdevice_resource->DCM_in_polarity ? 1 : 0); /* usb mode */
gpio_set_value(pdevice_resource->USUS_in, pdevice_resource->USUS_in_polarity ? 0 : 1); /* usb suspend */
pdevice_resource->suspend_gpio_config();
printk(KERN_INFO "%s: CURRENT_ZERO\n", __func__);
break;
case CURRENT_100MA:
gpio_set_value(pdevice_resource->DCM_in, pdevice_resource->DCM_in_polarity? 1 : 0); /* usb mode */
gpio_set_value(pdevice_resource->IUSB_in, pdevice_resource->IUSB_in_polarity ? 1 : 0);/* usb 100mA */
gpio_set_value(pdevice_resource->USUS_in, pdevice_resource->USUS_in_polarity ? 1 : 0);
gpio_set_value(pdevice_resource->CEN_N_in, pdevice_resource->CEN_N_in_polarity ? 1 : 0); /* charger enable */
printk(KERN_INFO "%s: CURRENT_100MA\n", __func__);
break;
case CURRENT_500MA:
gpio_set_value(pdevice_resource->DCM_in, pdevice_resource->DCM_in_polarity ? 1 : 0); /* usb mode */
gpio_set_value(pdevice_resource->IUSB_in, pdevice_resource->IUSB_in_polarity ? 0 : 1); /* usb 500mA */
gpio_set_value(pdevice_resource->USUS_in, pdevice_resource->USUS_in_polarity ? 1 : 0);
gpio_set_value(pdevice_resource->CEN_N_in, pdevice_resource->CEN_N_in_polarity ? 1 : 0); /* charger enable */
printk(KERN_INFO "%s: CURRENT_500MA\n", __func__);
break;
case CURRENT_750MA:
case CURRENT_900MA:
case CURRENT_1000MA:
case CURRENT_1400MA:
case CURRENT_1500MA:
case CURRENT_2000MA:
gpio_set_value(pdevice_resource->DCM_in, pdevice_resource->DCM_in_polarity ? 0 : 1); /* DC mode */
if (pdevice_resource->set_DC_CHG_Mode_current) {
if (pdevice_resource->set_DC_CHG_Mode_current(value) != 0) {
current_limit = old_current_limit;
}
} else {
printk(KERN_NOTICE "%s: set_DC_CHG_Mode_current is NULL\n", __func__);
}
gpio_set_value(pdevice_resource->CEN_N_in, pdevice_resource->CEN_N_in_polarity ? 1 : 0); /* charger enable */
printk(KERN_INFO "%s: CURRENT_750(4), 900(5), 1000(6), 1400(7), 2000MA(9): %d\n", __func__, value);
break;
default:
current_limit = old_current_limit;
printk(KERN_INFO "%s: Not supported current setting\n", __func__);
rc = -EINVAL;
break;
}
return rc;
}
static void max8903b_hw_init()
{
gpio_set_value(pdevice_resource->DCM_in, pdevice_resource->DCM_in_polarity ? 1 : 0); /* usb mode */
gpio_set_value(pdevice_resource->IUSB_in, pdevice_resource->IUSB_in_polarity ? 0 : 1); /* usb 500mA */
gpio_set_value(pdevice_resource->USUS_in, pdevice_resource->USUS_in_polarity ? 1 : 0);
gpio_set_value(pdevice_resource->CEN_N_in, pdevice_resource->CEN_N_in_polarity ? 1 : 0); /* charger enable */
}
/* /sys/power/charger/status */
/*
* - DC-input OK
* - Charge in progress
* - Charge Done
* - Charge stop w/Fault
*/
/* /sys/power/charger/charging */
/*
* Show the current current limit setting.
*/
static ssize_t show_currentlimit(struct device *dev, struct device_attribute *attr,
char *buf)
{
char *str;
//printk(KERN_INFO "show_currentlimit! \n");
switch (current_limit) {
case CHARGE_DISABLE:
str = "none"; break;
case CURRENT_ZERO:
str = "current0ma"; break;
case CURRENT_100MA:
str = "current100ma"; break;
case CURRENT_500MA:
str = "current500ma"; break;
case CURRENT_750MA:
str = "current750ma"; break;
case CURRENT_900MA:
str = "current900ma"; break;
case CURRENT_1000MA:
str = "current1000ma"; break;
case CURRENT_1400MA:
str = "current1400ma"; break;
case CURRENT_1500MA:
str = "current1500ma"; break;
case CURRENT_2000MA:
str = "current2000ma"; break;
default:
return 0;
}
return snprintf(buf, PAGE_SIZE, "%s\n", str);
}
/**
* Parse the input for a charging command and optional current limit.
*/
static ssize_t store_currentlimit(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
enum max8903b_current value;
//printk(KERN_INFO "store_currentlimit! \n");
if (strncmp(buf, "off", 3) == 0 || strncmp(buf, "none", 4) == 0) {
value = CHARGE_DISABLE;
}
else if (strncmp(buf, "current0ma", 10) == 0) {
value = CURRENT_ZERO;
}
else if (strncmp(buf, "current100ma", 12) == 0) {
value = CURRENT_100MA;
}
else if (strncmp(buf, "current500ma", 12) == 0) {
value = CURRENT_500MA;
}
else if (strncmp(buf, "current750ma", 12) == 0) {
value = CURRENT_750MA;
}
else if (strncmp(buf, "current900ma", 12) == 0) {
value = CURRENT_900MA;
}
else if (strncmp(buf, "current1000ma", 13) == 0) {
value = CURRENT_1000MA;
}
else if (strncmp(buf, "current1400ma", 13) == 0) {
value = CURRENT_1400MA;
}
else if (strncmp(buf, "current1500ma", 13) == 0) {
value = CURRENT_1500MA;
}
else if (strncmp(buf, "current2000ma", 13) == 0) {
value = CURRENT_2000MA;
}
else {
printk(KERN_INFO "Invalid charging command: %s\n", buf);
return 0;
}
max8903b_current_setup(value);
return count;
}
void max8903b_set_charge_ma (unsigned ma)
{
enum max8903b_current value;
switch (ma){
case 0:
value = CURRENT_ZERO; break;
case 100:
value = CURRENT_100MA; break;
case 500:
value = CURRENT_500MA; break;
case 750:
value = CURRENT_750MA; break;
case 900:
value = CURRENT_900MA; break;
case 1000:
value = CURRENT_1000MA; break;
case 1400:
value = CURRENT_1400MA; break;
case 1500:
value = CURRENT_1500MA; break;
case 2000:
value = CURRENT_2000MA; break;
default:
printk(KERN_INFO "%s: Invalid value: %d\n", __func__, ma);
return;
}
if (current_limit != value) max8903b_current_setup(value);
return;
}
EXPORT_SYMBOL (max8903b_set_charge_ma);
void max8903b_disable_charge()
{
max8903b_current_setup(CHARGE_DISABLE);
}
EXPORT_SYMBOL (max8903b_disable_charge);
/* /sys/power/charger/chargerstatus */
/*
* Show the current current limit setting.
*/
static ssize_t show_chargerstatus(struct device *dev, struct device_attribute *attr,
char *buf)
{
char *str;
int dc_ok, fault, status;
if ( (dc_ok = gpio_get_value(pdevice_resource->DOK_N_out)) != 0) /* invalid DC-In */
str = "InvalidDC"; /* invalid DC-in */
else if ( (fault = gpio_get_value(pdevice_resource->FLT_N_out)) == 0)
str = "fault"; /* charger stopped with fault */
else if ( (status = gpio_get_value(pdevice_resource->CHG_N_out)) == 0)
str = "progress"; /* charge in progress */
else
str = "completed"; /* charge completed */
dc_ok = gpio_get_value(pdevice_resource->DOK_N_out);
fault = gpio_get_value(pdevice_resource->FLT_N_out);
status = gpio_get_value(pdevice_resource->CHG_N_out);
// printk(KERN_INFO "chargerstatus %s! | DC_OK=%d, STAT=%d, FAULT=%d\n",
// str, dc_ok, status, fault);
return snprintf(buf, PAGE_SIZE, "%s\n", str);
}
static DEVICE_ATTR(currentlimit, S_IRUGO | S_IWUSR, show_currentlimit, store_currentlimit);
static DEVICE_ATTR(chargerstatus, S_IRUGO, show_chargerstatus, NULL);
static struct attribute *max8903b_power_sysfs_entries[] = {
&dev_attr_currentlimit.attr,
&dev_attr_chargerstatus.attr,
NULL
};
static struct attribute_group max8903b_power_attr_group = {
.name = NULL,
.attrs = max8903b_power_sysfs_entries
};
static int __devinit max8903b_charger_probe(struct platform_device *pdev)
{
struct max8903b_platform_data *pdata;
int ret;
pdata = pdev->dev.platform_data;
pdevice_resource = pdata;
pdata->request_release_gpios(1);
ret = sysfs_create_group(&pdev->dev.kobj, &max8903b_power_attr_group);
if (ret) {
dev_err(&pdev->dev, "failed to create sysfs 'charger' entries\n");
} else {
ret = sysfs_create_link(power_kobj, &pdev->dev.kobj, "charger");
if (ret)
dev_err(&pdev->dev, "failed to create sysfs 'charger' link\n");
}
//max8903b_hw_init();
return 0;
}
static int __devexit max8903b_charger_remove(struct platform_device *pdev)
{
struct max8903b_platform_data *pdata;
pdata = pdev->dev.platform_data;
pdata->request_release_gpios(0);
return 0;
}
#ifdef CONFIG_PM
static int max8903b_resume(struct platform_device *pdev)
{
int rc = 0;
struct max8903b_platform_data *pdata;
pdata = pdev->dev.platform_data;
printk("%s: resume\n", __func__);
rc = pdata->request_release_gpios(1);
return rc;
}
static int max8903b_suspend(struct platform_device *pdev, pm_message_t state)
{
int rc = 0;
struct max8903b_platform_data *pdata;
pdata = pdev->dev.platform_data;
printk("%s: suspend\n", __func__);
rc = pdata->request_release_gpios(0);
return rc;
}
#endif
static struct platform_driver max8903b_charger_driver = {
.probe = max8903b_charger_probe,
.remove = __devexit_p(max8903b_charger_remove),
.driver = {
.name = "max8903b_chg",
.owner = THIS_MODULE,
},
#ifdef CONFIG_PM
.suspend = max8903b_suspend,
.resume = max8903b_resume,
#endif
};
static int __init max8903b_charger_init(void)
{
int rc;
rc = platform_driver_register(&max8903b_charger_driver);
if (rc ==0)
printk(KERN_INFO "max8903b driver registeration! rc = %d\n", rc);
else
printk(KERN_DEBUG "NO max8903b driver registeration!");
return rc;
}
static void __exit max8903b_charger_exit(void)
{
platform_driver_unregister(&max8903b_charger_driver);
}
module_init(max8903b_charger_init);
module_exit(max8903b_charger_exit);
MODULE_DESCRIPTION("MAX8903B battery charger driver");
MODULE_AUTHOR("Kyoung Kim <kyoung-il.kim@hp.com><kyoung.kim@palm.com>");
MODULE_LICENSE("GPL v2");

View File

@@ -0,0 +1,38 @@
#ifndef _LINUX_MAX8903B_CHARGER_H
#define _LINUX_MAX8903B_CHARGER_H
enum max8903b_current {
CHARGE_DISABLE,
CURRENT_ZERO,
CURRENT_100MA,
CURRENT_500MA,
CURRENT_750MA,
CURRENT_900MA,
CURRENT_1000MA,
CURRENT_1400MA,
CURRENT_1500MA,
CURRENT_2000MA,
};
struct max8903b_platform_data {
int DCM_in;
int DCM_in_polarity;
int IUSB_in;
int IUSB_in_polarity;
int USUS_in;
int USUS_in_polarity;
int CEN_N_in;
int CEN_N_in_polarity;
int DOK_N_out;
int CHG_N_out;
int FLT_N_out;
int (*set_DC_CHG_Mode_current)(enum max8903b_current value);
int (*request_release_gpios)(int request);
void (*suspend_gpio_config)(void);
};
void max8903b_set_charge_ma (unsigned ma);
void max8903b_disable_charge (void);
#endif