/*++ drivers/regulator/gmt2214.c 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/err.h> #include <linux/i2c.h> #include <linux/platform_device.h> #include <linux/regulator/driver.h> #include <linux/slab.h> #ifdef CONFIG_HAS_EARLYSUSPEND #include <linux/earlysuspend.h> #endif #include <linux/regulator/machine.h> #include <mach/hardware.h> #include <linux/interrupt.h> #include <asm/unaligned.h> #include <linux/delay.h> #include <mach/gmt-core.h> #undef DEBUG #ifdef DEBUG #define DPRINTK(fmt, args...) do { printk(KERN_DEBUG fmt , ##args); } while (0) #else #define DPRINTK(fmt, args...) do { } while (0) #endif #define GMT_DC1_MAX_STAGE 16 #define GMT_DC2_MAX_STAGE 16 #define GMT_LDOX_MAX_STAGE 2 #define GMT_LDO56_MAX_STAGE 4 #define GMT_DC1_MIN_UV 1050000 #define GMT_DC1_MAX_UV 1500000 #define GMT_DC2_MIN_UV 1050000 #define GMT_DC2_MAX_UV 1500000 #define GMTV1_DC1_MIN_UV 1000000 #define GMTV1_DC1_MAX_UV 1400000 #define GMTV1_DC2_MIN_UV 1000000 #define GMTV1_DC2_MAX_UV 1400000 #define DC1_REG_IDX 4 #define DC2_REG_IDX 4 #define DC1_REG_SHIFT 4 #define DC2_REG_SHIFT 0 #define DC1_REG_MASK 0xf0 #define DC2_REG_MASK 0xf #define LDXEN_REG_IDX 2 #define GMT_LDOX_MIN_UV 1050000 #define GMT_LDOX_MAX_UV 1500000 #define LDO56_REG_IDX 3 #define LDO5_REG_SHIFT 2 #define LDO6_REG_SHIFT 0 #define LDO5_REG_MASK 0x0c #define LDO6_REG_MASK 0x03 #define GMT_LDO56_MIN_UV 1500000 #define GMT_LDO56_MAX_UV 3300000 #define SUPPORT_DC_NUM 7 /* #define DEBUG */ extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen); static unsigned int g_i2cbus_id = 2; static unsigned int g_pmic_en = 0; static unsigned int gmt_version = 0; struct gmt_data { struct i2c_client *client; struct gmt2214_dev *gmt_dev; struct device *dev; unsigned int dc1_min_uV; unsigned int dc1_max_uV; unsigned int dc1_current_uV; unsigned int dc2_current_uV; unsigned int dc2_min_uV; unsigned int dc2_max_uV; unsigned char enabled; char regs[14]; struct regulator_dev *rdev; }; static struct gmt_data *g_gmtdata; static unsigned int delay_time = 400;/*us*/ static unsigned int swap_dc1_dc2 = 0; static int early_suspend_stage = 0; static int i2cWriteToGMT(struct gmt2214_dev *gmt2214, unsigned char bufferIndex, unsigned char value) { return gmt2214_reg_write(gmt2214, bufferIndex, value); } #ifdef DEBUG static int i2cReadFromGMT(struct i2c_client *client, unsigned char bufferIndex, unsigned char dataBuffer[], unsigned short dataLength) { int ret; struct i2c_msg msgs[2] = { { .addr = client->addr, .flags = I2C_M_NOSTART, .len = 1, .buf = &bufferIndex }, { .addr = client->addr, .flags = I2C_M_RD, .len = dataLength, .buf = dataBuffer } }; memset(dataBuffer, 0x00, dataLength); ret = i2c_transfer(client->adapter, msgs, 2); return ret; } #endif static int gmt_read_i2c(struct gmt2214_dev *gmt_2214, u8 reg, int *rt_value) { int err; if (!rt_value) return -EINVAL; err = gmt2214_reg_read(gmt_2214, reg, rt_value); if (err < 0) return err; g_gmtdata->regs[reg] = *rt_value; /* printk("reg = %x, value = %x\n", reg, g_gmtdata->regs[reg]); */ return 0; } static int gmt_dc1_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV, unsigned *selector) { struct gmt_data *gmt = rdev_get_drvdata(rdev); struct gmt2214_dev *gmt_dev = gmt->gmt_dev; u8 dc1_prog = 0; int ret = 0; int retry_count = 10; dc1_prog = gmt->regs[DC1_REG_IDX]; if (min_uV > gmt->dc1_max_uV || max_uV < gmt->dc1_min_uV) return -EINVAL; if (max_uV > gmt->dc1_max_uV) return -EINVAL; if (min_uV < gmt->dc1_min_uV) min_uV = gmt->dc1_min_uV; if (gmt_version == 0) { if (min_uV < 1200000) { if ((min_uV - gmt->dc1_min_uV) % 50000) *selector = ((min_uV - gmt->dc1_min_uV) / 50000) + 1; else *selector = (min_uV - gmt->dc1_min_uV) / 50000; } else { if ((min_uV - 1200000) % 25000) *selector = ((min_uV - 1200000) / 25000) + 1; else *selector = (min_uV - 1200000) / 25000; *selector += 3; } } else { if (min_uV >= 1400000) *selector = 15; else { if ((min_uV - 1000000) % 25000) *selector = ((min_uV - 1000000) / 25000) + 1; else *selector = (min_uV - 1000000) / 25000; } } if (!swap_dc1_dc2) { dc1_prog &= ~DC1_REG_MASK; dc1_prog |= *selector << DC1_REG_SHIFT; } else { dc1_prog &= ~DC2_REG_MASK; dc1_prog |= *selector << DC2_REG_SHIFT; } /* printk("changing voltage dc1 to %duv\n", min_uV); printk("dc1_prog = %x\n", dc1_prog); */ if (early_suspend_stage == 1) return ret; while (retry_count > 0) { ret = i2cWriteToGMT(gmt_dev, DC1_REG_IDX, dc1_prog); if (ret >= 0) break; --retry_count; } if (ret < 0) return ret; gmt->regs[DC1_REG_IDX] = dc1_prog; usleep_range(delay_time, delay_time + 50); gmt->dc1_current_uV = min_uV; return ret; } static int gmt_dc1_update_voltage(void) { unsigned int tmp_buf = 0; int current_uV; int ret = 0; ret = gmt_read_i2c(g_gmtdata->gmt_dev, DC1_REG_IDX, &tmp_buf); if (!swap_dc1_dc2) { tmp_buf &= DC1_REG_MASK; tmp_buf >>= DC1_REG_SHIFT; } else { tmp_buf &= DC2_REG_MASK; tmp_buf >>= DC2_REG_SHIFT; } if (gmt_version == 0) { if (tmp_buf < 3) current_uV = 1050000 + tmp_buf * 50000; else { tmp_buf -= 3; current_uV = 1200000 + tmp_buf * 25000; } } else { if (tmp_buf == 0xf) current_uV = 1400000; else current_uV = 1000000 + tmp_buf * 25000; } g_gmtdata->dc1_current_uV = current_uV; return ret; } static int gmt_dc1_get_voltage(struct regulator_dev *rdev) { struct gmt_data *gmt = rdev_get_drvdata(rdev); u32 tmp_buf = 0; unsigned int current_uV; int ret = 0; ret = gmt_read_i2c(gmt->gmt_dev, DC1_REG_IDX, &tmp_buf); if (!swap_dc1_dc2) { tmp_buf &= DC1_REG_MASK; tmp_buf >>= DC1_REG_SHIFT; } else { tmp_buf &= DC2_REG_MASK; tmp_buf >>= DC2_REG_SHIFT; } if (gmt_version == 0) { if (tmp_buf < 3) current_uV = 1050000 + tmp_buf * 50000; else { tmp_buf -= 3; current_uV = 1200000 + tmp_buf * 25000; } } else { if (tmp_buf == 0xf) current_uV = 1400000; else current_uV = 1000000 + tmp_buf * 25000; } gmt->dc1_current_uV = current_uV; return gmt->dc1_current_uV; } static int gmt_dc1_is_enabled(struct regulator_dev *rdev) { struct gmt_data *gmt = rdev_get_drvdata(rdev); if (gmt->enabled == 1) return 0; else return -EDOM; return 0; } static int _gmt_dc2_set_voltage(struct regulator_dev *rdev, int uV) { struct gmt_data *gmt = rdev_get_drvdata(rdev); struct gmt2214_dev *gmt_dev = gmt->gmt_dev; int retry_count = 10; unsigned selector; int ret = 0; u8 dc2_prog; dc2_prog = gmt->regs[DC2_REG_IDX]; /* if ((uV - gmt->dc2_min_uV) % 25000) selector = ((uV - gmt->dc2_min_uV) / 25000) + 1; else selector = (uV - gmt->dc2_min_uV) / 25000; */ if (gmt_version == 0) { if (uV < 1200000) { if ((uV - gmt->dc2_min_uV) % 50000) selector = ((uV - gmt->dc2_min_uV) / 50000) + 1; else selector = (uV - gmt->dc2_min_uV) / 50000; } else { if ((uV - 1200000) % 25000) selector = ((uV - 1200000) / 25000) + 1; else selector = (uV - 1200000) / 25000; selector += 3; } } else { if (uV >= 1400000) selector = 15; else { if ((uV - 1000000) % 25000) selector = ((uV - 1000000) / 25000) + 1; else selector = (uV - 1000000) / 25000; } } if (!swap_dc1_dc2) { dc2_prog &= ~DC2_REG_MASK; dc2_prog |= selector << DC2_REG_SHIFT; } else { dc2_prog &= ~DC1_REG_MASK; dc2_prog |= selector << DC1_REG_SHIFT; } /* printk("dc2_prog = %x\n", dc2_prog); */ while (retry_count > 0) { ret = i2cWriteToGMT(gmt_dev, DC2_REG_IDX, dc2_prog); if (ret >= 0) break; --retry_count; } gmt->regs[DC2_REG_IDX] = dc2_prog; return selector; } extern void wmt_mc5_autotune(void); static int gmt_dc2_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV, unsigned *selector) { struct gmt_data *gmt = rdev_get_drvdata(rdev); int ret = 0; int i = 0; int adj_uV; if (min_uV > gmt->dc2_max_uV || max_uV < gmt->dc2_min_uV) return -EINVAL; if (max_uV > gmt->dc2_max_uV) return -EINVAL; if (min_uV < gmt->dc2_min_uV) min_uV = gmt->dc2_min_uV; /* printk("current_uV = %d, min_uV = %d\n", gmt->dc2_current_uV, min_uV); */ if (gmt->dc2_current_uV > min_uV) { while (gmt->dc2_current_uV >= min_uV + i * 50000) { if (i != 0) { adj_uV = gmt->dc2_current_uV - i * 50000; /* printk("adj_uV = %d\n", adj_uV); */ *selector = _gmt_dc2_set_voltage(rdev, adj_uV); usleep_range(delay_time, delay_time + 50); wmt_mc5_autotune(); } ++i; } --i; if (gmt->dc2_current_uV != min_uV + i * 50000) { adj_uV = min_uV; *selector = _gmt_dc2_set_voltage(rdev, adj_uV); usleep_range(delay_time, delay_time + 50); } } else { while (gmt->dc2_current_uV + i * 50000 <= min_uV) { if (i != 0) { adj_uV = gmt->dc2_current_uV + i * 50000; /* printk("adj uV = %d\n", adj_uV); */ *selector = _gmt_dc2_set_voltage(rdev, gmt->dc2_current_uV + i * 50000); usleep_range(delay_time, delay_time + 50); wmt_mc5_autotune(); } ++i; } --i; if (gmt->dc2_current_uV != min_uV + i * 50000) { adj_uV = min_uV; *selector = _gmt_dc2_set_voltage(rdev, adj_uV); usleep_range(delay_time, delay_time + 50); } } gmt->dc2_current_uV = min_uV; return ret; } static unsigned int gmt_read_version(void) { unsigned int ver = 0; int ret = 0; ret = gmt_read_i2c(g_gmtdata->gmt_dev, 13, &ver); ver &= 0x30; ver >>= 4; return ver; #if 0 unsigned int ver = 0; int ret = 0; g_gmtdata->gmt_dev->i2c->addr = 0x01; while(g_gmtdata->gmt_dev->i2c->addr < 0x80){ printk("addr:0x%x, ret: %d\n", g_gmtdata->gmt_dev->i2c->addr, gmt_read_i2c(g_gmtdata->gmt_dev, 13, &ver)); ver &= 0x30; ver >>= 4; g_gmtdata->gmt_dev->i2c->addr++; } return ver; #endif } static int gmt_dc2_update_voltage(void) { unsigned int tmp_buf = 0; int current_uV; int ret = 0; ret = gmt_read_i2c(g_gmtdata->gmt_dev, DC2_REG_IDX, &tmp_buf); if (!swap_dc1_dc2) { tmp_buf &= DC2_REG_MASK; tmp_buf >>= DC2_REG_SHIFT; } else { tmp_buf &= DC1_REG_MASK; tmp_buf >>= DC1_REG_SHIFT; } if (gmt_version == 0) { if (tmp_buf < 3) current_uV = 1050000 + tmp_buf * 50000; else { tmp_buf -= 3; current_uV = 1200000 + tmp_buf * 25000; } } else { if (tmp_buf == 0xf) current_uV = 1400000; else current_uV = 1000000 + tmp_buf * 25000; } g_gmtdata->dc2_current_uV = current_uV; return ret; } static int gmt_dc2_get_voltage(struct regulator_dev *rdev) { struct gmt_data *gmt = rdev_get_drvdata(rdev); u32 tmp_buf = 0; unsigned int current_uV; int ret = 0; ret = gmt_read_i2c(gmt->gmt_dev, DC2_REG_IDX, &tmp_buf); if (!swap_dc1_dc2) { tmp_buf &= DC2_REG_MASK; tmp_buf >>= DC2_REG_SHIFT; } else { tmp_buf &= DC1_REG_MASK; tmp_buf >>= DC1_REG_SHIFT; } if (gmt_version == 0) { if (tmp_buf < 3) current_uV = 1050000 + tmp_buf * 50000; else { tmp_buf -= 3; current_uV = 1200000 + tmp_buf * 25000; } } else { if (tmp_buf == 0xf) current_uV = 1400000; else current_uV = 1000000 + tmp_buf * 25000; } gmt->dc2_current_uV = current_uV; return gmt->dc2_current_uV; } static int recovery_ldox_state(void) { unsigned int ret = 0; ret = i2cWriteToGMT(g_gmtdata->gmt_dev, LDXEN_REG_IDX, g_gmtdata->regs[LDXEN_REG_IDX]); return ret; } static int update_ldox_state(void) { unsigned int tmp_buf; unsigned int ret; ret = gmt_read_i2c(g_gmtdata->gmt_dev, LDXEN_REG_IDX, &tmp_buf); g_gmtdata->regs[LDXEN_REG_IDX] = (unsigned char)tmp_buf; return ret; } static int gmt_dc2_is_enabled(struct regulator_dev *rdev) { struct gmt_data *gmt = rdev_get_drvdata(rdev); if (gmt->enabled == 1) return 0; else return -EDOM; return 0; } static int gmt_ldox_enable(struct regulator_dev *rdev, unsigned int ldo_num) { struct gmt_data *gmt = rdev_get_drvdata(rdev); unsigned char reg_val; unsigned int tmp_buf; if (ldo_num < 2 || ldo_num > 6) return -1; gmt_read_i2c(g_gmtdata->gmt_dev, LDXEN_REG_IDX, &tmp_buf); gmt->regs[LDXEN_REG_IDX] = (unsigned char)tmp_buf; reg_val = gmt->regs[LDXEN_REG_IDX]; switch (ldo_num) { case 2: reg_val |= BIT7; i2cWriteToGMT(gmt->gmt_dev, LDXEN_REG_IDX, reg_val); gmt->regs[LDXEN_REG_IDX] |= BIT7; break; case 3: reg_val |= BIT6; i2cWriteToGMT(gmt->gmt_dev, LDXEN_REG_IDX, reg_val); gmt->regs[LDXEN_REG_IDX] |= BIT6; break; case 4: reg_val |= BIT5; i2cWriteToGMT(gmt->gmt_dev, LDXEN_REG_IDX, reg_val); gmt->regs[LDXEN_REG_IDX] |= BIT5; break; case 5: reg_val |= BIT4; i2cWriteToGMT(gmt->gmt_dev, LDXEN_REG_IDX, reg_val); gmt->regs[LDXEN_REG_IDX] |= BIT4; break; case 6: reg_val |= BIT3; i2cWriteToGMT(gmt->gmt_dev, LDXEN_REG_IDX, reg_val); gmt->regs[LDXEN_REG_IDX] |= BIT3; break; } return 0; } static int gmt_ldox_disable(struct regulator_dev *rdev, unsigned int ldo_num) { struct gmt_data *gmt = rdev_get_drvdata(rdev); unsigned char reg_val; unsigned int tmp_buf = 0; if (ldo_num < 2 || ldo_num > 6) return -1; gmt_read_i2c(g_gmtdata->gmt_dev, LDXEN_REG_IDX, &tmp_buf); gmt->regs[LDXEN_REG_IDX] = (unsigned char)tmp_buf; reg_val = gmt->regs[LDXEN_REG_IDX]; switch (ldo_num) { case 2: reg_val &= ~BIT7; i2cWriteToGMT(gmt->gmt_dev, LDXEN_REG_IDX, reg_val); gmt->regs[LDXEN_REG_IDX] &= ~BIT7; break; case 3: reg_val &= ~BIT6; i2cWriteToGMT(gmt->gmt_dev, LDXEN_REG_IDX, reg_val); gmt->regs[LDXEN_REG_IDX] &= ~BIT6; break; case 4: reg_val &= ~BIT5; i2cWriteToGMT(gmt->gmt_dev, LDXEN_REG_IDX, reg_val); gmt->regs[LDXEN_REG_IDX] &= ~BIT5; break; case 5: reg_val &= ~BIT4; i2cWriteToGMT(gmt->gmt_dev, LDXEN_REG_IDX, reg_val); gmt->regs[LDXEN_REG_IDX] &= ~BIT4; break; case 6: reg_val &= ~BIT3; i2cWriteToGMT(gmt->gmt_dev, LDXEN_REG_IDX, reg_val); gmt->regs[LDXEN_REG_IDX] &= ~BIT3; break; } return 0; } static int get_ldox_state(struct regulator_dev *rdev, unsigned int ldo_num) { unsigned int tmp_buf = 0; struct gmt_data *gmt = rdev_get_drvdata(rdev); if (ldo_num < 2 || ldo_num > 6) return -1; gmt_read_i2c(gmt->gmt_dev, LDXEN_REG_IDX, &tmp_buf); if (tmp_buf & (0x1 << (9 - ldo_num))) return 1;/*enabled*/ else return 0; } static int gmt_ldo2_is_enabled(struct regulator_dev *rdev) { return get_ldox_state(rdev, 2); } static int gmt_ldo2_enable(struct regulator_dev *rdev) { gmt_ldox_enable(rdev, 2); return 0; } static int gmt_ldo2_disable(struct regulator_dev *rdev) { gmt_ldox_disable(rdev, 2); return 0; } static int gmt_ldo3_is_enabled(struct regulator_dev *rdev) { return get_ldox_state(rdev, 3); } static int gmt_ldo3_enable(struct regulator_dev *rdev) { gmt_ldox_enable(rdev, 3); return 0; } static int gmt_ldo3_disable(struct regulator_dev *rdev) { gmt_ldox_disable(rdev, 3); return 0; } static int gmt_ldo4_is_enabled(struct regulator_dev *rdev) { return get_ldox_state(rdev, 4); } static int gmt_ldo4_enable(struct regulator_dev *rdev) { gmt_ldox_enable(rdev, 4); return 0; } static int gmt_ldo4_disable(struct regulator_dev *rdev) { gmt_ldox_disable(rdev, 4); return 0; } static int gmt_ldo5_is_enabled(struct regulator_dev *rdev) { return get_ldox_state(rdev, 5); } static int gmt_ldo5_enable(struct regulator_dev *rdev) { gmt_ldox_enable(rdev, 5); return 0; } static int gmt_ldo5_disable(struct regulator_dev *rdev) { gmt_ldox_disable(rdev, 5); return 0; } static int gmt_ldo6_is_enabled(struct regulator_dev *rdev) { return get_ldox_state(rdev, 6); } static int gmt_ldo6_enable(struct regulator_dev *rdev) { gmt_ldox_enable(rdev, 6); return 0; } static int gmt_ldo6_disable(struct regulator_dev *rdev) { gmt_ldox_disable(rdev, 6); return 0; } static int gmt_ldo56_list_voltage(struct regulator_dev *rdev, unsigned selector) { int ret; switch (selector) { case 0: ret = 1500000; break; case 1: ret = 1800000; break; case 2: ret = 2800000; break; case 3: ret = 3300000; break; default: ret = -1; break; } return ret; } static int gmt_ldo56_set_voltage_sel(struct regulator_dev *rdev, unsigned selector) { struct gmt_data *gmt = rdev_get_drvdata(rdev); const char *rdev_name = rdev->desc->name; u8 reg_val = gmt->regs[LDO56_REG_IDX]; if (!strcmp(rdev_name, "ldo5")) { reg_val &= ~LDO5_REG_MASK; reg_val |= ((selector << LDO5_REG_SHIFT) & LDO5_REG_MASK); } else if (!strcmp(rdev_name, "ldo6")) { reg_val &= ~LDO6_REG_MASK; reg_val |= ((selector << LDO6_REG_SHIFT) & LDO6_REG_MASK); } else return -EINVAL; i2cWriteToGMT(gmt->gmt_dev, LDO56_REG_IDX, reg_val); gmt->regs[LDO56_REG_IDX] = reg_val; return 0; } static struct regulator_ops gmt_dc1_ops = { .set_voltage = gmt_dc1_set_voltage, .is_enabled = gmt_dc1_is_enabled, .get_voltage = gmt_dc1_get_voltage, }; static struct regulator_ops gmt_dc2_ops = { .set_voltage = gmt_dc2_set_voltage, .is_enabled = gmt_dc2_is_enabled, .get_voltage = gmt_dc2_get_voltage, }; static struct regulator_ops gmt_ldo2_ops = { .enable = gmt_ldo2_enable, .disable = gmt_ldo2_disable, .is_enabled = gmt_ldo2_is_enabled, }; static struct regulator_ops gmt_ldo3_ops = { .enable = gmt_ldo3_enable, .disable = gmt_ldo3_disable, .is_enabled = gmt_ldo3_is_enabled, }; static struct regulator_ops gmt_ldo4_ops = { .enable = gmt_ldo4_enable, .disable = gmt_ldo4_disable, .is_enabled = gmt_ldo4_is_enabled, }; static struct regulator_ops gmt_ldo5_ops = { .enable = gmt_ldo5_enable, .disable = gmt_ldo5_disable, .is_enabled = gmt_ldo5_is_enabled, .list_voltage = gmt_ldo56_list_voltage, .set_voltage_sel = gmt_ldo56_set_voltage_sel, }; static struct regulator_ops gmt_ldo6_ops = { .enable = gmt_ldo6_enable, .disable = gmt_ldo6_disable, .is_enabled = gmt_ldo6_is_enabled, .list_voltage = gmt_ldo56_list_voltage, .set_voltage_sel = gmt_ldo56_set_voltage_sel, }; static struct regulator_desc gmt_reg[] = { { .name = "wmt_corepower", .id = 0, .ops = &gmt_dc1_ops, .type = REGULATOR_VOLTAGE, .n_voltages = GMT_DC1_MAX_STAGE, .owner = THIS_MODULE, }, { .name = "wmt_vdd", .id = 0, .ops = &gmt_dc2_ops, .type = REGULATOR_VOLTAGE, .n_voltages = GMT_DC2_MAX_STAGE, .owner = THIS_MODULE, }, { .name = "ldo2", .id = 0, .ops = &gmt_ldo2_ops, .type = REGULATOR_VOLTAGE, .n_voltages = GMT_LDOX_MAX_STAGE, .owner = THIS_MODULE, }, { .name = "ldo3", .id = 0, .ops = &gmt_ldo3_ops, .type = REGULATOR_VOLTAGE, .n_voltages = GMT_LDOX_MAX_STAGE, .owner = THIS_MODULE, }, { .name = "ldo4", .id = 0, .ops = &gmt_ldo4_ops, .type = REGULATOR_VOLTAGE, .n_voltages = GMT_LDOX_MAX_STAGE, .owner = THIS_MODULE, }, { .name = "ldo5", .id = 0, .ops = &gmt_ldo5_ops, .type = REGULATOR_VOLTAGE, .n_voltages = GMT_LDO56_MAX_STAGE, .owner = THIS_MODULE, }, { .name = "ldo6", .id = 0, .ops = &gmt_ldo6_ops, .type = REGULATOR_VOLTAGE, .n_voltages = GMT_LDO56_MAX_STAGE, .owner = THIS_MODULE, }, }; static struct regulator_consumer_supply gmt_dc1_supply = REGULATOR_SUPPLY("wmt_corepower", NULL); static struct regulator_consumer_supply gmt_dc2_supply = REGULATOR_SUPPLY("wmt_vdd", NULL); static struct regulator_consumer_supply gmt_ldo2_supply = REGULATOR_SUPPLY("ldo2", NULL); static struct regulator_consumer_supply gmt_ldo3_supply = REGULATOR_SUPPLY("ldo3", NULL); static struct regulator_consumer_supply gmt_ldo4_supply = REGULATOR_SUPPLY("ldo4", NULL); static struct regulator_consumer_supply gmt_ldo5_supply = REGULATOR_SUPPLY("ldo5", NULL); static struct regulator_consumer_supply gmt_ldo6_supply = REGULATOR_SUPPLY("ldo6", NULL); static struct regulator_init_data gmt_dc1_power = { .constraints = { .min_uV = GMT_DC1_MIN_UV, .max_uV = GMT_DC1_MAX_UV, .apply_uV = true, .valid_modes_mask = REGULATOR_MODE_NORMAL | REGULATOR_MODE_STANDBY, .valid_ops_mask = REGULATOR_CHANGE_MODE | REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE, }, .num_consumer_supplies = 1, .consumer_supplies = &gmt_dc1_supply, }; static struct regulator_init_data gmtv1_dc1_power = { .constraints = { .min_uV = GMTV1_DC1_MIN_UV, .max_uV = GMTV1_DC1_MAX_UV, .apply_uV = true, .valid_modes_mask = REGULATOR_MODE_NORMAL | REGULATOR_MODE_STANDBY, .valid_ops_mask = REGULATOR_CHANGE_MODE | REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE, }, .num_consumer_supplies = 1, .consumer_supplies = &gmt_dc1_supply, }; static struct regulator_init_data gmt_dc2_power = { .constraints = { .min_uV = GMT_DC2_MIN_UV, .max_uV = GMT_DC2_MAX_UV, .apply_uV = true, .valid_modes_mask = REGULATOR_MODE_NORMAL | REGULATOR_MODE_STANDBY, .valid_ops_mask = REGULATOR_CHANGE_MODE | REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE, }, .num_consumer_supplies = 1, .consumer_supplies = &gmt_dc2_supply, }; static struct regulator_init_data gmtv1_dc2_power = { .constraints = { .min_uV = GMTV1_DC2_MIN_UV, .max_uV = GMTV1_DC2_MAX_UV, .apply_uV = true, .valid_modes_mask = REGULATOR_MODE_NORMAL | REGULATOR_MODE_STANDBY, .valid_ops_mask = REGULATOR_CHANGE_MODE | REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE, }, .num_consumer_supplies = 1, .consumer_supplies = &gmt_dc2_supply, }; static struct regulator_init_data gmt_ldo2_power = { .constraints = { .min_uV = GMT_LDOX_MIN_UV, .max_uV = GMT_LDOX_MAX_UV, .apply_uV = true, .valid_modes_mask = REGULATOR_MODE_NORMAL | REGULATOR_MODE_STANDBY, .valid_ops_mask = REGULATOR_CHANGE_MODE | REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE, }, .num_consumer_supplies = 1, .consumer_supplies = &gmt_ldo2_supply, }; static struct regulator_init_data gmt_ldo3_power = { .constraints = { .min_uV = GMT_LDOX_MIN_UV, .max_uV = GMT_LDOX_MAX_UV, .apply_uV = true, .valid_modes_mask = REGULATOR_MODE_NORMAL | REGULATOR_MODE_STANDBY, .valid_ops_mask = REGULATOR_CHANGE_MODE | REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE, }, .num_consumer_supplies = 1, .consumer_supplies = &gmt_ldo3_supply, }; static struct regulator_init_data gmt_ldo4_power = { .constraints = { .min_uV = GMT_LDOX_MIN_UV, .max_uV = GMT_LDOX_MAX_UV, .apply_uV = true, .valid_modes_mask = REGULATOR_MODE_NORMAL | REGULATOR_MODE_STANDBY, .valid_ops_mask = REGULATOR_CHANGE_MODE | REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE, }, .num_consumer_supplies = 1, .consumer_supplies = &gmt_ldo4_supply, }; static struct regulator_init_data gmt_ldo5_power = { .constraints = { .min_uV = GMT_LDO56_MIN_UV, .max_uV = GMT_LDO56_MAX_UV, .apply_uV = true, .valid_modes_mask = REGULATOR_MODE_NORMAL | REGULATOR_MODE_STANDBY, .valid_ops_mask = REGULATOR_CHANGE_MODE | REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE, }, .num_consumer_supplies = 1, .consumer_supplies = &gmt_ldo5_supply, }; static struct regulator_init_data gmt_ldo6_power = { .constraints = { .min_uV = GMT_LDO56_MIN_UV, .max_uV = GMT_LDO56_MAX_UV, .apply_uV = true, .valid_modes_mask = REGULATOR_MODE_NORMAL | REGULATOR_MODE_STANDBY, .valid_ops_mask = REGULATOR_CHANGE_MODE | REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_VOLTAGE, }, .num_consumer_supplies = 1, .consumer_supplies = &gmt_ldo6_supply, }; #ifdef CONFIG_PM static int g2214_read(u8 reg) { unsigned int rt_value =0; gmt2214_reg_read(g_gmtdata->gmt_dev, reg, &rt_value); return rt_value; } static void g2214reg_dump(void) { printk("reg A%d: 0x%x\n ", 0, g2214_read(0)); printk("reg A%d: 0x%x\n ", 1, g2214_read(1)); printk("reg A%d: 0x%x\n ", 2, g2214_read(2)); printk("reg A%d: 0x%x\n ", 3, g2214_read(3)); printk("reg A%d: 0x%x\n ", 4, g2214_read(4)); printk("reg A%d: 0x%x\n ", 5, g2214_read(5)); printk("reg A%d: 0x%x\n ", 6, g2214_read(6)); printk("reg A%d: 0x%x\n ", 7, g2214_read(7)); printk("reg A%d: 0x%x\n ", 8, g2214_read(8)); printk("reg A%d: 0x%x\n ", 9, g2214_read(9)); printk("reg A%d: 0x%x\n ", 10, g2214_read(10)); printk("reg A%d: 0x%x\n ", 11, g2214_read(11)); printk("reg A%d: 0x%x\n ", 12, g2214_read(12)); printk("reg A%d: 0x%x\n ", 13, g2214_read(13)); } static int gmt_i2c_suspend(struct device *dev) { int ret=0; g_gmtdata->enabled = 0; early_suspend_stage = 1; printk(KERN_ERR "%s: =============\n", __func__); #ifdef G2214_DUMP g2214reg_dump(); #endif if (ret) { printk(KERN_ERR "%s: Buck mode can't set to be auto mode.\n", __func__); return ret; } return ret; } static int gmt_i2c_resume(struct device *dev) { int ret=0; printk(KERN_ERR "%s: =============\n", __func__); if (ret) { printk(KERN_ERR "%s: Buck mode can't set to be force PWM mode.\n", __func__); return ret; } gmt_dc2_update_voltage(); gmt_dc1_update_voltage(); recovery_ldox_state(); g_gmtdata->enabled = 1; #ifdef G2214_DUMP g2214reg_dump(); #endif early_suspend_stage = 0; return ret; } static SIMPLE_DEV_PM_OPS(gmt_dev_pm_ops, gmt_i2c_suspend, gmt_i2c_resume); #endif static int __devinit gmt_pmic_probe(struct platform_device *pdev) { struct regulator_dev *rdev; struct regulator_init_data *initdata; struct gmt_data *gmt; int ret = 0; gmt = kzalloc(sizeof(struct gmt_data) + SUPPORT_DC_NUM * sizeof(struct regulator_dev *), GFP_KERNEL); if (!gmt) goto out; gmt->gmt_dev = dev_get_drvdata(pdev->dev.parent); gmt->dev = &pdev->dev; gmt->enabled = 1; g_gmtdata = gmt; gmt_version = gmt_read_version(); rdev = &gmt->rdev[0]; if (gmt_version == 1) initdata = &gmtv1_dc1_power; else initdata = &gmt_dc1_power; rdev = regulator_register(&gmt_reg[0], gmt->dev, initdata, gmt, NULL); rdev = &gmt->rdev[1]; if (gmt_version == 1) initdata = &gmtv1_dc2_power; else initdata = &gmt_dc2_power; rdev = regulator_register(&gmt_reg[1], gmt->dev, initdata, gmt, NULL); rdev = &gmt->rdev[2]; initdata = &gmt_ldo2_power; rdev = regulator_register(&gmt_reg[2], gmt->dev, initdata, gmt, NULL); rdev = &gmt->rdev[3]; initdata = &gmt_ldo3_power; rdev = regulator_register(&gmt_reg[3], gmt->dev, initdata, gmt, NULL); rdev = &gmt->rdev[4]; initdata = &gmt_ldo4_power; rdev = regulator_register(&gmt_reg[4], gmt->dev, initdata, gmt, NULL); rdev = &gmt->rdev[5]; initdata = &gmt_ldo5_power; rdev = regulator_register(&gmt_reg[5], gmt->dev, initdata, gmt, NULL); rdev = &gmt->rdev[6]; initdata = &gmt_ldo6_power; rdev = regulator_register(&gmt_reg[6], gmt->dev, initdata, gmt, NULL); platform_set_drvdata(pdev, gmt); if (gmt_version == 0) { gmt->dc1_min_uV = GMT_DC1_MIN_UV; gmt->dc1_max_uV = GMT_DC1_MAX_UV; gmt->dc2_min_uV = GMT_DC2_MIN_UV; gmt->dc2_max_uV = GMT_DC2_MAX_UV; } else { gmt->dc1_min_uV = GMTV1_DC1_MIN_UV; gmt->dc1_max_uV = GMTV1_DC1_MAX_UV; gmt->dc2_min_uV = GMTV1_DC2_MIN_UV; gmt->dc2_max_uV = GMTV1_DC2_MAX_UV; } gmt_dc2_update_voltage(); gmt_dc1_update_voltage(); update_ldox_state(); printk("GMT PMIC ver:0x%x\n", gmt_version); dev_info(gmt->dev, "GMT regulator driver loaded\n"); return 0; out: return ret; } static int __devexit gmt_pmic_remove(struct platform_device *pdev) { struct gmt_data *gmt = platform_get_drvdata(pdev); regulator_unregister(gmt->rdev); kfree(gmt); return 0; } #define par_len 80 static int parse_pmic_param(void) { int retval; unsigned char buf[par_len]; unsigned char tmp_buf[par_len]; int i = 0; int j = 0; int varlen = par_len; char *varname = "wmt.pmic.param"; unsigned int pmic_en = 0; retval = wmt_getsyspara(varname, buf, &varlen); if (retval == 0) { pmic_en = (buf[i] - '0' == 1)?1:0; if (pmic_en == 0) {/*disable*/ g_pmic_en = 0; return -1; } i += 2; for (; i < par_len; ++i) { if (buf[i] == ':') break; tmp_buf[j] = buf[i]; ++j; } if (strncmp(tmp_buf,"gmt2214",7)) { g_pmic_en = 0; return -1; } ++i; sscanf((buf + i), "%d:%d:%d", &g_i2cbus_id, &delay_time, &swap_dc1_dc2); } else { g_pmic_en = 0; return -1; } g_pmic_en = 1; return 0; } static struct platform_driver gmt_pmic_driver = { .probe = gmt_pmic_probe, .remove = __devexit_p(gmt_pmic_remove), .driver = { .name = "gmt-pmic", .owner = THIS_MODULE, #ifdef CONFIG_PM .pm = &gmt_dev_pm_ops, #endif }, }; static int __init gmt_pmic_init(void) { parse_pmic_param(); printk("GMT2214_PMIC_INIT\n"); if (g_pmic_en == 0) { printk("No gmt pmic\n"); return -ENODEV; } return platform_driver_register(&gmt_pmic_driver); } module_init(gmt_pmic_init); static void __exit gmt_pmic_exit(void) { platform_driver_unregister(&gmt_pmic_driver); } module_exit(gmt_pmic_exit); MODULE_AUTHOR("WonderMedia Technologies, Inc."); MODULE_DESCRIPTION("GMT2214 Driver"); MODULE_LICENSE("GPL");