예제 #1
0
static int max8998_charging_control(struct chg_data *chg)
{
	int ret;
	struct i2c_client *i2c = chg->iodev->i2c;

	if (!chg->charging) {
		/* disable charging */
		ret = max8998_update_reg(i2c, MAX8998_REG_CHGR2,
			(1 << MAX8998_SHIFT_CHGEN), MAX8998_MASK_CHGEN);
		if (ret < 0)
			goto err;

		pr_debug("%s : charging disabled\n", __func__);
	} else {
		/* enable charging */
		if (chg->cable_status == CABLE_TYPE_AC) {
			/* ac */
			ret = max8998_write_reg(i2c, MAX8998_REG_CHGR1,
						(2 << MAX8998_SHIFT_TOPOFF) |
						(3 << MAX8998_SHIFT_RSTR) |
						(5 << MAX8998_SHIFT_ICHG));
			if (ret < 0)
				goto err;

			pr_debug("%s : TA charging enabled\n", __func__);
		} else {
			/* usb */
			ret = max8998_write_reg(i2c, MAX8998_REG_CHGR1,
						(6 << MAX8998_SHIFT_TOPOFF) |
						(3 << MAX8998_SHIFT_RSTR) |
						(2 << MAX8998_SHIFT_ICHG));
			if (ret < 0)
				goto err;

			pr_debug("%s : USB charging enabled\n", __func__);
		}

		ret = max8998_write_reg(i2c, MAX8998_REG_CHGR2,
					(2 << MAX8998_SHIFT_ESAFEOUT) |
					(2 << MAX8998_SHIFT_FT) |
					(0 << MAX8998_SHIFT_CHGEN));
		if (ret < 0)
			goto err;
	}

	return 0;
err:
	pr_err("max8998_read_reg error\n");
	return ret;
}
예제 #2
0
static irqreturn_t max8998_int_work_func(int irq, void *max8998_chg)
{
	int ret;
	u8 data[MAX8998_NUM_IRQ_REGS];

	struct chg_data *chg = max8998_chg;
        struct i2c_client *i2c = chg->iodev->i2c;

	ret = max8998_bulk_read(i2c, MAX8998_REG_IRQ1, MAX8998_NUM_IRQ_REGS, data);
	if (ret < 0)
		goto err;

	wake_lock(&chg->work_wake_lock);

#ifndef TOPOFF_CURRENT_CHECK
	if (data[MAX8998_REG_IRQ3] & MAX8998_IRQ_TOPOFFR_MASK) {
		bat_info("%s : topoff intr(%d)\n", __func__, chg->set_batt_full);
		if (chg->set_batt_full)
			chg->bat_info.batt_is_full = true;
		else {
			chg->set_batt_full = true;

			if (chg->cable_status == CABLE_TYPE_AC)
				max8998_write_reg(i2c, MAX8998_REG_CHGR1,
					(MAX8998_TOPOFF_10	<< MAX8998_SHIFT_TOPOFF) |
					(MAX8998_RSTR_DISABLE	<< MAX8998_SHIFT_RSTR) |
					(MAX8998_ICHG_600	<< MAX8998_SHIFT_ICHG));
			else if (chg->cable_status == CABLE_TYPE_USB)
				max8998_write_reg(i2c, MAX8998_REG_CHGR1,
					(MAX8998_TOPOFF_10	<< MAX8998_SHIFT_TOPOFF) |
					(MAX8998_RSTR_DISABLE	<< MAX8998_SHIFT_RSTR) |
					(MAX8998_ICHG_475	<< MAX8998_SHIFT_ICHG));
		}
	}
#endif

	if (data[MAX8998_REG_IRQ4] & MAX8998_IRQ_LOBAT1_MASK)
		max8998_lowbat_warning(chg);

	if (data[MAX8998_REG_IRQ4] & MAX8998_IRQ_LOBAT2_MASK)
		max8998_lowbat_critical(chg);

	queue_work(chg->monitor_wqueue, &chg->bat_work);

	return IRQ_HANDLED;
err:
	pr_err("%s : pmic read error\n", __func__);
	return IRQ_HANDLED;
}
예제 #3
0
int max8998_set_dvsint_direct(u32 armSet, u32 voltage)
{
	struct max8998_data *max8998 = client_data_p;
        int reg, i, value;
	DBG("func =%s called with set=%d, voltage=%d",__func__, armSet, voltage);
	if(armSet == DVSINT1)
		reg = MAX8998_REG_DVSINT1;
	else if(armSet == DVSINT2)
		reg = MAX8998_REG_DVSINT2;	
	else {
		printk("Invalid parameter for dvs int\n");
		return -EINVAL;
	}

	for( i =0; i < sizeof(dcdc12_voltage_map)/4; i++)
	{
		if(dcdc12_voltage_map[i] == voltage)
			break;
	}
	if(i == sizeof(dcdc12_voltage_map)/4)
	{
		printk("Invalid parameter of voltage value for dvs int\n");
		return -EINVAL;
	}

	value = i;
	max8998_write_reg(max8998, value, reg);	
	return 0;
}
예제 #4
0
static int max8998_rtc_stop_alarm(struct max8998_rtc_info *info)
{
	int ret = max8998_write_reg(info->rtc, MAX8998_ALARM0_CONF, 0);

	if (info->lp3974_bug_workaround)
		msleep(2000);

	return ret;
}
예제 #5
0
파일: max8998.c 프로젝트: 020gzh/linux
/* Restore registers after hibernation */
static int max8998_restore(struct device *dev)
{
	struct i2c_client *i2c = to_i2c_client(dev);
	int i;

	for (i = 0; i < ARRAY_SIZE(max8998_dump); i++)
		max8998_write_reg(i2c, max8998_dump[i].addr,
				max8998_dump[i].val);

	return 0;
}
예제 #6
0
int max8998_ldo_disable_direct(int ldo)
{
	struct max8998_data *max8998 = client_data_p;
	int value, shift;

	if((ldo < MAX8998_LDO1) || (ldo > MAX8998_DCDC4))
	{
		printk("ERROR: Invalid argument passed\n");
		return -EINVAL;
	}

	DBG("func =%s called for regulator = %d\n",__func__,ldo);

	spin_lock(&pmic_access_lock);

	if (ldo <= MAX8998_LDO5) {
		value = max8998_read_reg(max8998, MAX8998_REG_ONOFF1);
		shift = 5 - ldo;
		value &= ~(1 << shift);
		max8998_write_reg(max8998, value, MAX8998_REG_ONOFF1);
	} else if (ldo <= MAX8998_LDO13) {
		value = max8998_read_reg(max8998, MAX8998_REG_ONOFF2);
		shift = 13 - ldo;
		value &= ~(1 << shift);
		max8998_write_reg(max8998, value, MAX8998_REG_ONOFF2);
	} else if (ldo <= MAX8998_LDO17) {
		value = max8998_read_reg(max8998, MAX8998_REG_ONOFF3);
		shift = 21 - ldo;
		value &= ~(1 << shift);
		max8998_write_reg(max8998, value, MAX8998_REG_ONOFF3);
	} else {
		value = max8998_read_reg(max8998, MAX8998_REG_ONOFF1);
		shift = 7 - (ldo - MAX8998_DCDC1);
		value &= ~(1 << shift);
		max8998_write_reg(max8998, value, MAX8998_REG_ONOFF1);
	}

	spin_unlock(&pmic_access_lock);

	return 0;
}
예제 #7
0
static irqreturn_t max8998_int_work_func(int irq, void *max8998_chg)
{
	int ret;
	u8 data[MAX8998_NUM_IRQ_REGS];

	struct chg_data *chg = max8998_chg;
        struct i2c_client *i2c = chg->iodev->i2c;

	ret = max8998_bulk_read(i2c, MAX8998_REG_IRQ1, MAX8998_NUM_IRQ_REGS, data);
	if (ret < 0)
		goto err;

	wake_lock(&chg->work_wake_lock);

	if (data[MAX8998_REG_IRQ3] & MAX8998_IRQ_TOPOFFR_MASK) {
		bat_info("%s : topoff intr(%d)\n", __func__, chg->set_batt_full);
		if (chg->set_batt_full)
			chg->bat_info.batt_is_full = true;
		else {
			chg->set_batt_full = true;

			if (chg->cable_status == CABLE_TYPE_AC)
#if defined(CONFIG_ARIES_NTT)
				max8998_write_reg(i2c, MAX8998_REG_CHGR1,
					(MAX8998_TOPOFF_10	<< MAX8998_SHIFT_TOPOFF) |
					(MAX8998_RSTR_DISABLE	<< MAX8998_SHIFT_RSTR) |
					(MAX8998_ICHG_700	<< MAX8998_SHIFT_ICHG));
#else
				max8998_write_reg(i2c, MAX8998_REG_CHGR1,
					(MAX8998_TOPOFF_10	<< MAX8998_SHIFT_TOPOFF) |
					(MAX8998_RSTR_DISABLE	<< MAX8998_SHIFT_RSTR) |
					(MAX8998_ICHG_600	<< MAX8998_SHIFT_ICHG));
#endif
			else if (chg->cable_status == CABLE_TYPE_USB)
				max8998_write_reg(i2c, MAX8998_REG_CHGR1,
					(MAX8998_TOPOFF_25	<< MAX8998_SHIFT_TOPOFF) |
					(MAX8998_RSTR_DISABLE	<< MAX8998_SHIFT_RSTR) |
					(MAX8998_ICHG_475	<< MAX8998_SHIFT_ICHG));
		}
예제 #8
0
static void s3c_bat_top_off(struct chg_data *chg)
{
	struct i2c_client *i2c = chg->iodev->i2c;

	bat_info("%s : topoff(%d)\n", __func__, chg->set_batt_full);
	if (chg->set_batt_full)
		chg->bat_info.batt_is_full = true;
	else {
		chg->set_batt_full = true;
	
		if (chg->cable_status == CABLE_TYPE_AC)
			max8998_write_reg(i2c, MAX8998_REG_CHGR1,
				(MAX8998_TOPOFF_10	<< MAX8998_SHIFT_TOPOFF) |
				(MAX8998_RSTR_DISABLE	<< MAX8998_SHIFT_RSTR) |
				(MAX8998_ICHG_600	<< MAX8998_SHIFT_ICHG));
		else if (chg->cable_status == CABLE_TYPE_USB)
			max8998_write_reg(i2c, MAX8998_REG_CHGR1,
				(MAX8998_TOPOFF_10	<< MAX8998_SHIFT_TOPOFF) |
				(MAX8998_RSTR_DISABLE	<< MAX8998_SHIFT_RSTR) |
				(MAX8998_ICHG_475	<< MAX8998_SHIFT_ICHG));
	}
}
예제 #9
0
static int max8998_ldo_disable(struct regulator_dev *rdev)
{
	struct max8998_data *max8998 = rdev_get_drvdata(rdev);
	int ldo = max8998_get_ldo(rdev);
	int value, shift;
	
	DBG("func =%s called for regulator = %d\n",__func__,ldo);

	spin_lock(&pmic_access_lock);

	if (ldo <= MAX8998_LDO5) {
		value = max8998_read_reg(max8998, MAX8998_REG_ONOFF1);
		//shift = 6 - ldo;
		shift = 5 - ldo;
		value &= ~(1 << shift);
		max8998_write_reg(max8998, value, MAX8998_REG_ONOFF1);
	} else if (ldo <= MAX8998_LDO13) {
		value = max8998_read_reg(max8998, MAX8998_REG_ONOFF2);
		shift = 13 - ldo;
		value &= ~(1 << shift);
		max8998_write_reg(max8998, value, MAX8998_REG_ONOFF2);
	} else if (ldo <= MAX8998_LDO17) {
		value = max8998_read_reg(max8998, MAX8998_REG_ONOFF3);
		shift = 21 - ldo;
		value &= ~(1 << shift);
		max8998_write_reg(max8998, value, MAX8998_REG_ONOFF3);
	} else {
		value = max8998_read_reg(max8998, MAX8998_REG_ONOFF1);
		shift = 7 - (ldo - MAX8998_DCDC1);
		value &= ~(1 << shift);
		max8998_write_reg(max8998, value, MAX8998_REG_ONOFF1);
	}

	spin_unlock(&pmic_access_lock);

	return 0;
}
예제 #10
0
static int max8998_rtc_start_alarm(struct max8998_rtc_info *info)
{
	int ret;
	u8 alarm0_conf = 0x77;

	/* LP3974 with delay bug chips has rtc alarm bugs with "MONTH" field */
	if (info->lp3974_bug_workaround)
		alarm0_conf = 0x57;

	ret = max8998_write_reg(info->rtc, MAX8998_ALARM0_CONF, alarm0_conf);

	if (info->lp3974_bug_workaround)
		msleep(2000);

	return ret;
}
static int max8998_rtc_start_alarm(struct max8998_rtc_info *info)
{
	int ret;
	u8 alarm0_conf = 0x77;

	
	if (info->lp3974_bug_workaround)
		alarm0_conf = 0x57;

	ret = max8998_write_reg(info->rtc, MAX8998_ALARM0_CONF, alarm0_conf);

	if (info->lp3974_bug_workaround)
		msleep(2000);

	return ret;
}
예제 #12
0
static int max8998_i2c_probe(struct i2c_client *i2c,
			    const struct i2c_device_id *id)
{
        struct max8998_platform_data *pdata = i2c->dev.platform_data;
	struct max8998_dev *max8998;
	int ret = 0;
	u8 val;

	max8998 = kzalloc(sizeof(struct max8998_dev), GFP_KERNEL);
	if (max8998 == NULL)
		return -ENOMEM;

	i2c_set_clientdata(i2c, max8998);
	max8998->dev = &i2c->dev;
	max8998->i2c_client = i2c;
	max8998->irq = i2c->irq;
	if (pdata) {
		max8998->ono = pdata->ono;
		max8998->irq_base = pdata->irq_base;
	}
	max8998->dev_read = max8998_i2c_device_read;
	max8998->dev_write = max8998_i2c_device_write;
	max8998->dev_update = max8998_i2c_device_update;
	mutex_init(&max8998->iolock);

	max8998_irq_init(max8998);

	max8998_read_reg(max8998, MAX8998_REG_ONOFF1, &val);
	val &= ~(MAX8998_MASK_EN1|MAX8998_MASK_EN2|MAX8998_MASK_EN4);
	max8998_write_reg(max8998, MAX8998_REG_ONOFF1, val);

	ret = mfd_add_devices(max8998->dev, -1,
			      max8998_devs, ARRAY_SIZE(max8998_devs),
			      NULL, 0);
	if (ret < 0)
		goto err;

	return ret;

err:
	mfd_remove_devices(max8998->dev);
	kfree(max8998);
	return ret;
}
예제 #13
0
int max8998_ldo_set_voltage_direct(int ldo,
				int min_uV, int max_uV)
{
	struct max8998_data *max8998 = client_data_p;
	int value, shift = 0, mask = 0xff, reg;
	int min_vol = min_uV / 1000, max_vol = max_uV / 1000;
	int i = 0;
	const int *vol_map = NULL;

	if((ldo < MAX8998_LDO1) || (ldo > MAX8998_DCDC4))
	{
		printk("ERROR: Invalid argument passed\n");
		return -EINVAL;
	}

	vol_map = ldo_voltage_map[ldo];
	DBG("func =%s called for regulator = %d, min_v=%d, max_v=%d\n",__func__,ldo,min_uV,max_uV);

	if (min_vol < 750 ||
	    max_vol > 3600)
		return -EINVAL;

	while (vol_map[i]) {
		if (vol_map[i] >= min_vol)
			break;
		i++;
	}
	
	DBG("Found voltage=%d\n",vol_map[i]);

	if (!vol_map[i])
		return -EINVAL;

	if (vol_map[i] > max_vol)
		return -EINVAL;

	if (ldo == MAX8998_LDO3) {
		reg  = MAX8998_REG_LDO23;
		mask = 0x0F;
	} else if (ldo == MAX8998_LDO2) {
		reg  = MAX8998_REG_LDO23;
		shift = 4;
		mask = 0x0F;
	} else if (ldo == MAX8998_LDO8) {
		reg  = MAX8998_REG_LDO89;
		shift = 4;
		mask = 0x07;
	} else if (ldo == MAX8998_LDO9) {
		reg  = MAX8998_REG_LDO89;
		shift = 2;
		mask = 0x03;
	} else if (ldo == MAX8998_LDO10) {
		reg  = MAX8998_REG_LDO1011;
		shift = 5;
		mask = 0x07;
	} else if (ldo == MAX8998_LDO11) {
		reg  = MAX8998_REG_LDO1011;
		mask = 0x1F;
	} else if (ldo == MAX8998_LDO12) {
		reg  = MAX8998_REG_LDO12;
		mask = 0xFF;
	} else if (ldo == MAX8998_LDO13) {
		reg  = MAX8998_REG_LDO13;
		mask = 0xFF;
	} else if (ldo == MAX8998_LDO14) {
		reg  = MAX8998_REG_LDO14;
		mask = 0xFF;
	} else if (ldo == MAX8998_LDO15) {
		reg  = MAX8998_REG_LDO15;
		mask = 0xFF;
	} else if (ldo == MAX8998_LDO16) {
		reg  = MAX8998_REG_LDO16;
		mask = 0xFF;
	} else if (ldo == MAX8998_LDO17) {
		reg  = MAX8998_REG_LDO17;
		mask = 0xFF;
	} else if (ldo == MAX8998_DCDC1) {
		//reg = 0x04;
		reg = MAX8998_REG_DVSARM1;
		mask = 0x1f;
	} else if (ldo == MAX8998_DCDC2) {
		//reg = 0x06;
		reg = MAX8998_REG_DVSINT1;
		mask = 0x1f;
	} else if (ldo == MAX8998_DCDC3) {
		reg = MAX8998_REG_BUCK3;
		mask = 0xff;
	} else if (ldo == MAX8998_DCDC4) {
		reg = MAX8998_REG_BUCK4;
		mask = 0xff;
	} else {// for ldo4,5,6,7
		reg = MAX8998_REG_LDO23 + (ldo - MAX8998_LDO3);
		mask = 0xff;
	}

	spin_lock(&pmic_access_lock);

	value = max8998_read_reg(max8998, reg);
	value &= ~(mask << shift);
	value |= (i << shift);
	max8998_write_reg(max8998, value, reg);

	spin_unlock(&pmic_access_lock);

	return 0;
}
예제 #14
0
static __devinit int max8998_charger_probe(struct platform_device *pdev)
{
	struct max8998_dev *iodev = dev_get_drvdata(pdev->dev.parent);
	struct max8998_platform_data *pdata = dev_get_platdata(iodev->dev);
	struct chg_data *chg;
	struct i2c_client *i2c = iodev->i2c;
	int ret = 0;

	pr_info("%s : MAX8998 Charger Driver Loading\n", __func__);

	chg = kzalloc(sizeof(*chg), GFP_KERNEL);
	if (!chg)
		return -ENOMEM;

	chg->iodev = iodev;
	chg->pdata = pdata->charger;

	if (!chg->pdata || !chg->pdata->adc_table) {
		pr_err("%s : No platform data & adc_table supplied\n", __func__);
		ret = -EINVAL;
		goto err_bat_table;
	}

	chg->psy_bat.name = "battery",
	chg->psy_bat.type = POWER_SUPPLY_TYPE_BATTERY,
	chg->psy_bat.properties = max8998_battery_props,
	chg->psy_bat.num_properties = ARRAY_SIZE(max8998_battery_props),
	chg->psy_bat.get_property = s3c_bat_get_property,
	chg->psy_bat.property_is_writeable = s3c_bat_property_is_writeable,
	chg->psy_bat.set_property = s3c_bat_set_property,

	chg->psy_usb.name = "usb",
	chg->psy_usb.type = POWER_SUPPLY_TYPE_USB,
	chg->psy_usb.supplied_to = supply_list,
	chg->psy_usb.num_supplicants = ARRAY_SIZE(supply_list),
	chg->psy_usb.properties = s3c_power_properties,
	chg->psy_usb.num_properties = ARRAY_SIZE(s3c_power_properties),
	chg->psy_usb.get_property = s3c_usb_get_property,

	chg->psy_ac.name = "ac",
	chg->psy_ac.type = POWER_SUPPLY_TYPE_MAINS,
	chg->psy_ac.supplied_to = supply_list,
	chg->psy_ac.num_supplicants = ARRAY_SIZE(supply_list),
	chg->psy_ac.properties = s3c_power_properties,
	chg->psy_ac.num_properties = ARRAY_SIZE(s3c_power_properties),
	chg->psy_ac.get_property = s3c_ac_get_property,

	chg->present = 1;
	chg->bat_info.batt_health = POWER_SUPPLY_HEALTH_GOOD;
	chg->bat_info.batt_is_full = false;
	chg->bat_info.batt_temp = 100; //fake
	chg->bat_info.batt_percentage = 50; //fake, modem will bootup soon and update it... hopefully
	chg->set_charge_timeout = false;

	chg->cable_status = CABLE_TYPE_NONE;

	mutex_init(&chg->mutex);

	platform_set_drvdata(pdev, chg);

	ret = max8998_update_reg(i2c, MAX8998_REG_CHGR1, /* disable */
		(0x3 << MAX8998_SHIFT_RSTR), MAX8998_MASK_RSTR);
	if (ret < 0)
		goto err_kfree;

	ret = max8998_update_reg(i2c, MAX8998_REG_CHGR2, /* 6 Hr */
		(0x2 << MAX8998_SHIFT_FT), MAX8998_MASK_FT);
	if (ret < 0)
		goto err_kfree;

	ret = max8998_update_reg(i2c, MAX8998_REG_CHGR2, /* 4.2V */
		(0x0 << MAX8998_SHIFT_BATTSL), MAX8998_MASK_BATTSL);
	if (ret < 0)
		goto err_kfree;

	ret = max8998_update_reg(i2c, MAX8998_REG_CHGR2, /* 105c */
		(0x0 << MAX8998_SHIFT_TMP), MAX8998_MASK_TMP);
	if (ret < 0)
		goto err_kfree;

	pr_info("%s : pmic interrupt registered\n", __func__);
	ret = max8998_write_reg(i2c, MAX8998_REG_IRQM1,
		~(MAX8998_MASK_DCINR | MAX8998_MASK_DCINF));
	if (ret < 0)
		goto err_kfree;

	ret = max8998_write_reg(i2c, MAX8998_REG_IRQM2, 0xFF);
	if (ret < 0)
		goto err_kfree;

	ret = max8998_write_reg(i2c, MAX8998_REG_IRQM3, ~MAX8998_IRQ_CHGRSTF_MASK);
	if (ret < 0)
		goto err_kfree;

	ret = max8998_write_reg(i2c, MAX8998_REG_IRQM4, 0xFF);
	if (ret < 0)
		goto err_kfree;

	wake_lock_init(&chg->vbus_wake_lock, WAKE_LOCK_SUSPEND,
		"vbus_present");
	wake_lock_init(&chg->work_wake_lock, WAKE_LOCK_SUSPEND,
		"max8998-charger");

	INIT_WORK(&chg->bat_work, s3c_bat_work);

	chg->monitor_wqueue =
		create_freezable_workqueue(dev_name(&pdev->dev));
	if (!chg->monitor_wqueue) {
		pr_err("Failed to create freezeable workqueue\n");
		ret = -ENOMEM;
		goto err_wake_lock;
	}

	chg->last_poll = alarm_get_elapsed_realtime();
	alarm_init(&chg->alarm, ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP,
		s3c_battery_alarm);

	check_lpm_charging_mode(chg);

	/* init power supplier framework */
	ret = power_supply_register(&pdev->dev, &chg->psy_bat);
	if (ret) {
		pr_err("Failed to register power supply psy_bat\n");
		goto err_wqueue;
	}

	ret = power_supply_register(&pdev->dev, &chg->psy_usb);
	if (ret) {
		pr_err("Failed to register power supply psy_usb\n");
		goto err_supply_unreg_bat;
	}

	ret = power_supply_register(&pdev->dev, &chg->psy_ac);
	if (ret) {
		pr_err("Failed to register power supply psy_ac\n");
		goto err_supply_unreg_usb;
	}

	ret = request_threaded_irq(iodev->i2c->irq, NULL,
			max8998_int_work_func,
			IRQF_TRIGGER_FALLING, "max8998-charger", chg);
	if (ret) {
		pr_err("%s : Failed to request pmic irq\n", __func__);
		goto err_supply_unreg_ac;
	}

	ret = enable_irq_wake(iodev->i2c->irq);
	if (ret) {
		pr_err("Failed to enable pmic irq wake\n");
		goto err_irq;
	}

	ret = s3c_bat_create_attrs(chg->psy_bat.dev);
	if (ret) {
		pr_err("%s : Failed to create_attrs\n", __func__);
		goto err_irq;
	}

	chg->callbacks.set_cable = max8998_set_cable;
	if (chg->pdata->register_callbacks)
		chg->pdata->register_callbacks(&chg->callbacks);

	wake_lock(&chg->work_wake_lock);
	queue_work(chg->monitor_wqueue, &chg->bat_work);

	return 0;

err_irq:
	free_irq(iodev->i2c->irq, NULL);
err_supply_unreg_ac:
	power_supply_unregister(&chg->psy_ac);
err_supply_unreg_usb:
	power_supply_unregister(&chg->psy_usb);
err_supply_unreg_bat:
	power_supply_unregister(&chg->psy_bat);
err_wqueue:
	destroy_workqueue(chg->monitor_wqueue);
	cancel_work_sync(&chg->bat_work);
	alarm_cancel(&chg->alarm);
err_wake_lock:
	wake_lock_destroy(&chg->work_wake_lock);
	wake_lock_destroy(&chg->vbus_wake_lock);
err_kfree:
	mutex_destroy(&chg->mutex);
err_bat_table:
	kfree(chg);
	return ret;
}
예제 #15
0
static int max8998_charging_control(struct chg_data *chg)
{
        struct i2c_client *i2c = chg->iodev->i2c;
	static int prev_charging = -1, prev_cable = -1;
	int ret;
	int topoff;

	if ((prev_charging == chg->charging) && (prev_cable == chg->cable_status))
		return 0;

	bat_info("%s : chg(%d) cable(%d) dis(%X) bat(%d,%d,%d), esafe(%d)\n", __func__,
		chg->charging, chg->cable_status, chg->bat_info.dis_reason,
		chg->bat_info.batt_soc, chg->set_batt_full, chg->bat_info.batt_is_full,
		chg->esafe);

	if (!chg->charging) {
		/* disable charging */
		s3c_clean_chg_current(chg);

		ret = max8998_write_reg(i2c, MAX8998_REG_CHGR2,
			(chg->esafe		<< MAX8998_SHIFT_ESAFEOUT) |
			(MAX8998_CHGTIME_7HR	<< MAX8998_SHIFT_FT) |
			(MAX8998_CHGEN_DISABLE	<< MAX8998_SHIFT_CHGEN));
		if (ret < 0)
			goto err;
	} else {
		/* enable charging */
		if (chg->cable_status == CABLE_TYPE_AC) {
			/* termination current adc NOT used to detect full-charging */
			if (chg->pdata->termination_curr_adc > 0)
				topoff = MAX8998_TOPOFF_10;
			else
				topoff = MAX8998_TOPOFF_30;

			/* ac */
			ret = max8998_write_reg(i2c, MAX8998_REG_CHGR1,
				(topoff	<< MAX8998_SHIFT_TOPOFF) |
				(MAX8998_RSTR_DISABLE	<< MAX8998_SHIFT_RSTR) |
				(MAX8998_ICHG_600	<< MAX8998_SHIFT_ICHG));
			if (ret < 0)
				goto err;

			ret = max8998_write_reg(i2c, MAX8998_REG_CHGR2,
				(chg->esafe		<< MAX8998_SHIFT_ESAFEOUT) |
				(MAX8998_CHGTIME_7HR	<< MAX8998_SHIFT_FT) |
				(MAX8998_CHGEN_ENABLE	<< MAX8998_SHIFT_CHGEN));
			if (ret < 0)
				goto err;
		} else {
			if (chg->pdata->termination_curr_adc > 0)
				topoff = MAX8998_TOPOFF_10;
			else
				topoff = MAX8998_TOPOFF_35;

			/* usb */
			ret = max8998_write_reg(i2c, MAX8998_REG_CHGR1,
				(topoff	<< MAX8998_SHIFT_TOPOFF) |
				(MAX8998_RSTR_DISABLE	<< MAX8998_SHIFT_RSTR) |
				(MAX8998_ICHG_475	<< MAX8998_SHIFT_ICHG));
			if (ret < 0)
				goto err;

			ret = max8998_write_reg(i2c, MAX8998_REG_CHGR2,
				(chg->esafe		<< MAX8998_SHIFT_ESAFEOUT) |
				(MAX8998_CHGTIME_7HR	<< MAX8998_SHIFT_FT) |
				(MAX8998_CHGEN_ENABLE	<< MAX8998_SHIFT_CHGEN));
			if (ret < 0)
				goto err;
		}
	}

	prev_charging = chg->charging;
	prev_cable = chg->cable_status;

	return 0;
err:
	pr_err("max8998_read_reg error\n");
	return ret;
}
예제 #16
0
static int max8998_charging_control(struct chg_data *chg)
{
        struct i2c_client *i2c = chg->iodev->i2c;
	static int prev_charging = -1, prev_cable = -1;
	int ret;

	if ((prev_charging == chg->charging) && (prev_cable == chg->cable_status))
		return 0;

	bat_info("%s : chg(%d) cable(%d) dis(%X) esafe(%d) bat(%d,%d,%d)\n", __func__,
		chg->charging, chg->cable_status, chg->bat_info.dis_reason, chg->esafe,
		chg->bat_info.batt_soc, chg->set_batt_full, chg->bat_info.batt_is_full);

	if (!chg->charging) {
		/* disable charging */
		ret = max8998_write_reg(i2c, MAX8998_REG_CHGR2,
			(chg->esafe		<< MAX8998_SHIFT_ESAFEOUT) |
			(MAX8998_CHGTIME_7HR	<< MAX8998_SHIFT_FT) |
			(MAX8998_CHGEN_DISABLE	<< MAX8998_SHIFT_CHGEN));
		if (ret < 0)
			goto err;
	} else {
		/* enable charging */
		if (chg->cable_status == CABLE_TYPE_AC) {
			/* ac */
#if defined(CONFIG_ARIES_NTT)
			if (chg->set_batt_full)
				ret = max8998_write_reg(i2c, MAX8998_REG_CHGR1,
					(MAX8998_TOPOFF_10	<< MAX8998_SHIFT_TOPOFF) |
					(MAX8998_RSTR_DISABLE	<< MAX8998_SHIFT_RSTR) |
					(MAX8998_ICHG_700	<< MAX8998_SHIFT_ICHG));
			else
				ret = max8998_write_reg(i2c, MAX8998_REG_CHGR1,
					(MAX8998_TOPOFF_15	<< MAX8998_SHIFT_TOPOFF) |
					(MAX8998_RSTR_DISABLE	<< MAX8998_SHIFT_RSTR) |
					(MAX8998_ICHG_700	<< MAX8998_SHIFT_ICHG));
#else
			if (chg->set_batt_full)
				ret = max8998_write_reg(i2c, MAX8998_REG_CHGR1,
					(MAX8998_TOPOFF_10	<< MAX8998_SHIFT_TOPOFF) |
					(MAX8998_RSTR_DISABLE	<< MAX8998_SHIFT_RSTR) |
					(MAX8998_ICHG_600	<< MAX8998_SHIFT_ICHG));
			else
				ret = max8998_write_reg(i2c, MAX8998_REG_CHGR1,
					(MAX8998_TOPOFF_20	<< MAX8998_SHIFT_TOPOFF) |
					(MAX8998_RSTR_DISABLE	<< MAX8998_SHIFT_RSTR) |
					(MAX8998_ICHG_600	<< MAX8998_SHIFT_ICHG));
#endif
			if (ret < 0)
				goto err;

			ret = max8998_write_reg(i2c, MAX8998_REG_CHGR2,
				(chg->esafe		<< MAX8998_SHIFT_ESAFEOUT) |
				(MAX8998_CHGTIME_7HR	<< MAX8998_SHIFT_FT) |
				(MAX8998_CHGEN_ENABLE	<< MAX8998_SHIFT_CHGEN));
			if (ret < 0)
				goto err;
		} else {
			/* usb */
			if (chg->set_batt_full)
				ret = max8998_write_reg(i2c, MAX8998_REG_CHGR1,
					(MAX8998_TOPOFF_25	<< MAX8998_SHIFT_TOPOFF) |
					(MAX8998_RSTR_DISABLE	<< MAX8998_SHIFT_RSTR) |
					(MAX8998_ICHG_475	<< MAX8998_SHIFT_ICHG));
			else
				ret = max8998_write_reg(i2c, MAX8998_REG_CHGR1,
					(MAX8998_TOPOFF_30	<< MAX8998_SHIFT_TOPOFF) |
					(MAX8998_RSTR_DISABLE	<< MAX8998_SHIFT_RSTR) |
					(MAX8998_ICHG_475	<< MAX8998_SHIFT_ICHG));
			if (ret < 0)
				goto err;

			ret = max8998_write_reg(i2c, MAX8998_REG_CHGR2,
				(chg->esafe		<< MAX8998_SHIFT_ESAFEOUT) |
				(MAX8998_CHGTIME_7HR	<< MAX8998_SHIFT_FT) |
				(MAX8998_CHGEN_ENABLE	<< MAX8998_SHIFT_CHGEN));
			if (ret < 0)
				goto err;
		}
	}

	prev_charging = chg->charging;
	prev_cable = chg->cable_status;

	return 0;
err:
	pr_err("max8998_read_reg error\n");
	return ret;
}
예제 #17
0
static __devinit int max8998_charger_probe(struct platform_device *pdev)
{
	struct max8998_dev *iodev = dev_get_drvdata(pdev->dev.parent);
	struct max8998_platform_data *pdata = dev_get_platdata(iodev->dev);
	struct chg_data *chg;
        struct i2c_client *i2c = iodev->i2c;
	int ret = 0;

	bat_info("%s : MAX8998 Charger Driver Loading\n", __func__);

	chg = kzalloc(sizeof(*chg), GFP_KERNEL);
	if (!chg)
		return -ENOMEM;

	chg->iodev = iodev;
	chg->pdata = pdata->charger;

	if (!chg->pdata || !chg->pdata->adc_table) {
		pr_err("%s : No platform data & adc_table supplied\n", __func__);
		ret = -EINVAL;
		goto err_bat_table;
	}

	chg->psy_bat.name = "battery";
	chg->psy_bat.type = POWER_SUPPLY_TYPE_BATTERY;
	chg->psy_bat.properties = max8998_battery_props;
	chg->psy_bat.num_properties = ARRAY_SIZE(max8998_battery_props);
	chg->psy_bat.get_property = s3c_bat_get_property;

	chg->psy_usb.name = "usb";
	chg->psy_usb.type = POWER_SUPPLY_TYPE_USB;
	chg->psy_usb.supplied_to = supply_list;
	chg->psy_usb.num_supplicants = ARRAY_SIZE(supply_list);
	chg->psy_usb.properties = s3c_power_properties;
	chg->psy_usb.num_properties = ARRAY_SIZE(s3c_power_properties);
	chg->psy_usb.get_property = s3c_usb_get_property;

	chg->psy_ac.name = "ac";
	chg->psy_ac.type = POWER_SUPPLY_TYPE_MAINS;
	chg->psy_ac.supplied_to = supply_list;
	chg->psy_ac.num_supplicants = ARRAY_SIZE(supply_list);
	chg->psy_ac.properties = s3c_power_properties;
	chg->psy_ac.num_properties = ARRAY_SIZE(s3c_power_properties);
	chg->psy_ac.get_property = s3c_ac_get_property;

	chg->present = 1;
	chg->bat_info.batt_health = POWER_SUPPLY_HEALTH_GOOD;
	chg->bat_info.batt_is_full = false;
	chg->set_batt_full = false;
	chg->set_charge_timeout = false;

	chg->cable_status = CABLE_TYPE_NONE;
	chg->esafe = MAX8998_USB_VBUS_AP_ON;

	mutex_init(&chg->mutex);

	platform_set_drvdata(pdev, chg);

	ret = max8998_write_reg(i2c, MAX8998_REG_IRQM1,
		~(MAX8998_IRQ_DCINR_MASK | MAX8998_IRQ_DCINF_MASK));
	if (ret < 0)
		goto err_kfree;

	ret = max8998_write_reg(i2c, MAX8998_REG_IRQM2, 0xFF);
	if (ret < 0)
		goto err_kfree;

#ifdef TOPOFF_CURRENT_CHECK
	ret = max8998_write_reg(i2c, MAX8998_REG_IRQM3, 0xFF);
#else
	ret = max8998_write_reg(i2c, MAX8998_REG_IRQM3, ~MAX8998_IRQ_TOPOFFR_MASK);
#endif
	if (ret < 0)
		goto err_kfree;

	ret = max8998_write_reg(i2c, MAX8998_REG_IRQM4,
		~(MAX8998_IRQ_LOBAT2_MASK | MAX8998_IRQ_LOBAT1_MASK));
	if (ret < 0)
		goto err_kfree;

	ret = max8998_update_reg(i2c, MAX8998_REG_ONOFF3,
		(1 << MAX8998_SHIFT_ENBATTMON), MAX8998_MASK_ENBATTMON);
	if (ret < 0)
		goto err_kfree;

	ret = max8998_update_reg(i2c, MAX8998_REG_LBCNFG1, 0x7, 0x37); //3.57V
	if (ret < 0)
		goto err_kfree;

	ret = max8998_update_reg(i2c, MAX8998_REG_LBCNFG2, 0x5, 0x37); //3.4V
	if (ret < 0)
		goto err_kfree;

	max8998_lowbat_config(chg, 0);

	wake_lock_init(&chg->vbus_wake_lock, WAKE_LOCK_SUSPEND, "vbus_present");
	wake_lock_init(&chg->work_wake_lock, WAKE_LOCK_SUSPEND, "max8998-charger");
	wake_lock_init(&chg->lowbat_wake_lock, WAKE_LOCK_SUSPEND, "max8998-lowbat");

	INIT_WORK(&chg->bat_work, s3c_bat_work);
	setup_timer(&chg->bat_work_timer, s3c_bat_work_timer_func, (unsigned long)chg);

	chg->monitor_wqueue = create_freezeable_workqueue(dev_name(&pdev->dev));
	if (!chg->monitor_wqueue) {
		pr_err("%s : Failed to create freezeable workqueue\n", __func__);
		ret = -ENOMEM;
		goto err_wake_lock;
	}

	check_lpm_charging_mode(chg);

	/* init power supplier framework */
	ret = power_supply_register(&pdev->dev, &chg->psy_bat);
	if (ret) {
		pr_err("%s : Failed to register power supply psy_bat\n", __func__);
		goto err_wqueue;
	}

	ret = power_supply_register(&pdev->dev, &chg->psy_usb);
	if (ret) {
		pr_err("%s : Failed to register power supply psy_usb\n", __func__);
		goto err_supply_unreg_bat;
	}

	ret = power_supply_register(&pdev->dev, &chg->psy_ac);
	if (ret) {
		pr_err("%s : Failed to register power supply psy_ac\n", __func__);
		goto err_supply_unreg_usb;
	}

	ret = request_threaded_irq(iodev->i2c->irq, NULL, max8998_int_work_func,
				   IRQF_TRIGGER_FALLING, "max8998-charger", chg);
	if (ret) {
		pr_err("%s : Failed to request pmic irq\n", __func__);
		goto err_supply_unreg_ac;
	}

	ret = enable_irq_wake(iodev->i2c->irq);
	if (ret) {
		pr_err("%s : Failed to enable pmic irq wake\n", __func__);
		goto err_irq;
	}

	ret = s3c_bat_create_attrs(chg->psy_bat.dev);
	if (ret) {
		pr_err("%s : Failed to create_attrs\n", __func__);
		goto err_irq;
	}

	chg->callbacks.set_cable = max8998_set_cable;
	chg->callbacks.set_esafe = max8998_set_esafe;
	chg->callbacks.get_vdcin = max8998_get_vdcin;
	if (chg->pdata->register_callbacks)
		chg->pdata->register_callbacks(&chg->callbacks);

	wake_lock(&chg->work_wake_lock);
	queue_work(chg->monitor_wqueue, &chg->bat_work);

	return 0;

err_irq:
	free_irq(iodev->i2c->irq, NULL);
err_supply_unreg_ac:
	power_supply_unregister(&chg->psy_ac);
err_supply_unreg_usb:
	power_supply_unregister(&chg->psy_usb);
err_supply_unreg_bat:
	power_supply_unregister(&chg->psy_bat);
err_wqueue:
	destroy_workqueue(chg->monitor_wqueue);
	cancel_work_sync(&chg->bat_work);
err_wake_lock:
	wake_lock_destroy(&chg->work_wake_lock);
	wake_lock_destroy(&chg->vbus_wake_lock);
	wake_lock_destroy(&chg->lowbat_wake_lock);
err_kfree:
	mutex_destroy(&chg->mutex);
err_bat_table:
	kfree(chg);
	return ret;
}