summaryrefslogtreecommitdiff
path: root/drivers/char/wmt-smb358.c
diff options
context:
space:
mode:
authorSrikant Patnaik2015-01-11 12:28:04 +0530
committerSrikant Patnaik2015-01-11 12:28:04 +0530
commit871480933a1c28f8a9fed4c4d34d06c439a7a422 (patch)
tree8718f573808810c2a1e8cb8fb6ac469093ca2784 /drivers/char/wmt-smb358.c
parent9d40ac5867b9aefe0722bc1f110b965ff294d30d (diff)
downloadFOSSEE-netbook-kernel-source-871480933a1c28f8a9fed4c4d34d06c439a7a422.tar.gz
FOSSEE-netbook-kernel-source-871480933a1c28f8a9fed4c4d34d06c439a7a422.tar.bz2
FOSSEE-netbook-kernel-source-871480933a1c28f8a9fed4c4d34d06c439a7a422.zip
Moved, renamed, and deleted files
The original directory structure was scattered and unorganized. Changes are basically to make it look like kernel structure.
Diffstat (limited to 'drivers/char/wmt-smb358.c')
-rwxr-xr-xdrivers/char/wmt-smb358.c393
1 files changed, 393 insertions, 0 deletions
diff --git a/drivers/char/wmt-smb358.c b/drivers/char/wmt-smb358.c
new file mode 100755
index 00000000..ae9ba4f5
--- /dev/null
+++ b/drivers/char/wmt-smb358.c
@@ -0,0 +1,393 @@
+/*++
+ drivers/char/wmt-smb358.c - SMB358 Battery charging driver
+
+ Copyright (c) 2013 WonderMedia Technologies, Inc.
+
+ This program is free software: you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software Foundation,
+ either version 2 of the License, or (at your option) any later version.
+
+ 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, see <http://www.gnu.org/licenses/>.
+
+ WonderMedia Technologies, Inc.
+ 10F, 529, Chung-Cheng Road, Hsin-Tien, Taipei 231, R.O.C.
+
+--*/
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/version.h>
+#include <mach/hardware.h>
+#include <linux/interrupt.h>
+#include <asm/irq.h>
+#include <linux/workqueue.h>
+#include <mach/wmt_mmap.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+DEFINE_MUTEX(charger_mutex);
+static int smb_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id);
+static unsigned int smb_read(unsigned int reg);
+
+static int smb_write(unsigned int reg, unsigned int value);
+static unsigned int g_battery_charging_en;
+static unsigned int g_i2cbus_id = 3;
+
+#ifdef CONFIG_MTD_WMT_SF
+extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen);
+#endif
+/*
+#define SMB358 1
+*/
+
+#ifdef SMB358
+#define smb_I2C_ADDR 0x6a /*SMB358*/
+#define SMB_NAME "smb358"
+#else
+#define smb_I2C_ADDR 0x6a /*SMB347*/
+#define SMB_NAME "smb347"
+#endif
+
+
+#define SUSGPIO0_EVENT_ID 0x10
+static struct i2c_client *smb_client;
+
+static struct workqueue_struct *smb_wq;
+struct work_struct smb_work;
+
+extern void pmc_enable_wakeup_event(unsigned int wakeup_event, unsigned int type);
+extern void pmc_disable_wakeup_event(unsigned int wakeup_event);
+extern int pmc_register_callback(unsigned int wakeup_event, void (*callback)(void *), void *callback_data);
+extern int pmc_unregister_callback(unsigned int wakeup_event);
+extern unsigned int pmc_get_wakeup_status(void);
+extern int udc_register_redetection(unsigned int delay_ms, void (*callback)(void *), void *callback_data);
+
+static void smb_enable_irq(void)
+{
+ pmc_enable_wakeup_event(SUSGPIO0_EVENT_ID, 4);
+}
+
+static void smb_disable_irq(void)
+{
+ pmc_disable_wakeup_event(SUSGPIO0_EVENT_ID);
+}
+
+static int smb_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+ int status;
+ int otg_status = 0;
+
+ printk("smb_suspend \n");
+ smb_disable_irq();
+ cancel_work_sync(&smb_work);
+#ifndef SMB358
+ otg_status = smb_read(0x30);
+ if (otg_status & BIT4) {
+ status = smb_read(0x0A);
+ status &= ~0xC;
+ status |= 0x4; /*set to 250mA*/
+ smb_write(0x0A, status);
+ }
+#endif
+
+ smb_write(0x30, 0x8a);/* OTG disable charging enable*/
+
+ return 0;
+}
+
+static int smb_resume(struct i2c_client *client)
+{
+ unsigned int wakeup_sts;
+ unsigned int otg_status;
+ wakeup_sts = pmc_get_wakeup_status();
+ printk("smb resume \n");
+
+ otg_status =REG32_VAL(0xFE110000) & 0x00200000;
+ /*Do work function in OTG mode*/
+ if (!otg_status)
+ queue_work(smb_wq, &smb_work);
+ smb_enable_irq();
+
+ return 0;
+}
+
+
+
+static const struct i2c_device_id smb_i2c_id[] = {
+ {SMB_NAME, 1},
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, smb_i2c_id);
+
+static struct i2c_driver smb_i2c_driver = {
+ .driver = {
+ .name = SMB_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = smb_i2c_probe,
+ .id_table = smb_i2c_id,
+ .suspend = smb_suspend,
+ .resume = smb_resume,
+
+};
+
+struct smb_conf_struct {
+ unsigned char bus_id;
+ struct i2c_client *client;
+ struct work_struct work;
+
+ struct i2c_adapter *i2c_adap;
+};
+static struct smb_conf_struct smb_conf;
+
+static struct i2c_board_info __initdata smb_board_info[] = {
+ {
+ I2C_BOARD_INFO(SMB_NAME, smb_I2C_ADDR),
+ },
+};
+
+static void smb_irq_callback(void *data)
+{
+ queue_work(smb_wq, &smb_work);
+}
+
+
+#ifdef CONFIG_MTD_WMT_SF
+static void parse_arg(void)
+{
+ int retval;
+ unsigned char buf[80];
+ unsigned char tmp_buf[80];
+ int varlen = 80;
+ char *varname = "wmt.bc.param";
+ int i = 0;
+ int j = 0;
+ retval = wmt_getsyspara(varname, buf, &varlen);
+ if (retval == 0) {
+ for (i = 0; i < 80; ++i) {
+ if (buf[i] == ':')
+ break;
+ g_battery_charging_en = (buf[i] - '0' == 1)?1:0;
+ if (g_battery_charging_en == 0)/*disable*/
+ return;
+ }
+ ++i;
+ for (; i < 80; ++i) {
+ if (buf[i] == ':')
+ break;
+ tmp_buf[j] = buf[i];
+ ++j;
+ }
+ if (!strncmp(tmp_buf,SMB_NAME,6))
+ g_battery_charging_en = 1;
+ else
+ g_battery_charging_en = 0;
+ ++i;
+ g_i2cbus_id = buf[i] - '0';
+ } else
+ g_battery_charging_en = 0;
+}
+#endif
+static int smb_modinit(void)
+{
+ int ret = 0;
+ struct i2c_adapter *adapter = NULL;
+ struct i2c_client *client = NULL;
+
+ printk(" smb_modinit \n");
+#ifdef CONFIG_MTD_WMT_SF
+ parse_arg();
+#endif
+
+ if (!g_battery_charging_en) {
+ printk("NO SMB358/347 \n");
+ return -EIO;
+ }
+ smb_conf.bus_id = g_i2cbus_id;
+ adapter = i2c_get_adapter(smb_conf.bus_id);
+ smb_conf.i2c_adap = adapter;
+ if (adapter == NULL) {
+ printk("can not get smb i2c adapter, client address error");
+ return -ENODEV;
+ }
+ if ((client=i2c_new_device(adapter, smb_board_info)) == NULL) {
+ printk("allocate smb i2c client failed");
+ return -ENOMEM;
+ }
+
+ ret = i2c_add_driver(&smb_i2c_driver);
+ if (ret)
+ printk("SMB 358/347 i2c fail\n");
+
+ return ret;
+}
+module_init(smb_modinit);
+
+static void smb_work_func(struct work_struct *work)
+{
+ int status;
+ int output_current_status = 0;
+
+ mutex_lock(&charger_mutex);
+#ifndef SMB358
+ status = smb_read(0x0A);
+#endif
+ status =REG32_VAL(0xFE110000) & 0x00200000;
+ if (!status ) {
+ printk("smb insert 0x30=0x98 with 500mA\n");
+ smb_write(0x30, 0x98); /* OTG enable charging disbale*/
+#ifndef SMB358
+ output_current_status = smb_read(0x0A);
+ output_current_status &= ~0xC;
+ output_current_status |= 0x8; /*set to 500mA*/
+ smb_write(0x0A, output_current_status);
+#endif
+ } else {
+#ifndef SMB358
+ output_current_status = smb_read(0x0A);
+ output_current_status &= ~0xC;
+ output_current_status |= 0x4; /* set to 250mA*/
+ smb_write(0x0A, output_current_status);
+#endif
+ printk("smb not insert 0x30=0x8a\n");
+ smb_write(0x30, 0x8a); /* OTG disable charging enable*/
+ }
+ mutex_unlock(&charger_mutex);
+}
+
+static void smb_power_src_redetection(void *data)
+{
+ int ret = 0;
+
+ mutex_lock(&charger_mutex);
+ ret = smb_write(0x30, 0xC0);
+ ret = smb_write(0x04, 0x08);
+ ret = smb_write(0x04, 0x0E);
+
+ mutex_unlock(&charger_mutex);
+
+ return;
+
+}
+static int smb_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct smb_conf_struct *smb;
+
+ int ret = 0;
+ int reg;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+ printk("SMB I2C_FUNC_I2C FAILED\n");
+ return -ENODEV;
+ }
+
+ smb = kzalloc(sizeof(*smb), GFP_KERNEL);
+ if (smb == NULL) {
+ printk("SMB FAIL\n");
+ return -ENOMEM;
+ }
+
+ smb->client = client;
+ smb_client = client;
+ i2c_set_clientdata(client,smb);
+
+ printk(" smb_i2c_probe \n");
+
+ smb_wq = create_workqueue("smb_wq");
+ if(smb_wq == NULL) {
+ printk("smb work fail \n");
+ return -ENOMEM;
+ }
+
+ INIT_WORK(&smb_work,smb_work_func);
+
+ reg = REG32_VAL(0xFE110000) & 0x00200000; /*read sus_gpio0 status*/
+ if (!reg) {
+ printk("smb insert 0x30=0x98\n");
+ smb_write(0x30, 0x98); /*OTG enable charging disbale*/
+ } else {
+ printk("smb not insert\n");
+ if (smb_read(0x3E) & 0x4) {/*USB_PC*/
+ printk("re-detection power source\n");
+ smb_power_src_redetection(client);
+ }
+ smb_write(0x30, 0x8a); /* OTG disable charging enable*/
+ }
+
+ /*
+ udc_register_redetection(1200, smb_power_src_redetection, client);
+ */
+ ret = pmc_register_callback(SUSGPIO0_EVENT_ID, smb_irq_callback, client);
+ if (ret == 0)
+ smb_enable_irq();
+ return ret;
+}
+
+static int smb_write(unsigned int reg, unsigned int value)
+{
+ int count;
+ struct i2c_msg msg[1];
+ unsigned char buf[2];
+ count=10;
+
+ while (count--) {
+ buf[0] = reg;
+ buf[1] = value;
+ msg[0].addr = smb_I2C_ADDR;
+ msg[0].flags = 0 ;
+ msg[0].flags &= ~(I2C_M_RD);
+ msg[0].len = 2;
+ msg[0].buf = buf;
+
+ if (i2c_transfer(smb_conf.i2c_adap, msg, ARRAY_SIZE(msg)) == ARRAY_SIZE(msg))
+ return 0;
+ }
+ printk(" error: i2c write reg[%02x]=%02x ", reg, value);
+ return -1;
+}
+
+static unsigned int smb_read(unsigned int reg)
+{
+ unsigned char buf[1];
+ struct i2c_msg msg[2];
+
+ msg[0].addr = smb_I2C_ADDR;
+ msg[0].flags = (2 | I2C_M_NOSTART);
+ msg[0].len = 1;
+ msg[0].buf = (unsigned char *)&reg;
+
+ msg[1].addr = smb_I2C_ADDR;
+ msg[1].flags = (I2C_M_RD | I2C_M_NOSTART);
+ msg[1].len = 1;
+ msg[1].buf = buf;
+
+ if (i2c_transfer(smb_conf.i2c_adap, msg, ARRAY_SIZE(msg)) == ARRAY_SIZE(msg))
+ return buf[0];
+
+ printk(" error: i2c read reg[%02x]", reg);
+ return -1;
+
+}
+
+static void __exit smb_exit(void)
+{
+ i2c_del_driver(&smb_i2c_driver);
+
+}
+module_exit(smb_exit);
+
+MODULE_DESCRIPTION("WMT SMB358/SMB347 driver");
+MODULE_AUTHOR("WonderMedia Technologies, Inc.");
+MODULE_LICENSE("GPL");