static int s2mu003_mfd_probe(struct i2c_client *i2c,
			    const struct i2c_device_id *id)
{
	int ret = 0;
	u8 data = 0;
	struct device_node *of_node = i2c->dev.of_node;
	s2mu003_mfd_chip_t *chip;
	s2mu003_mfd_platform_data_t *pdata = i2c->dev.platform_data;

	pr_info("%s : S2MU003 MFD Driver start probe\n", __func__);
	if (of_node) {
		pdata = devm_kzalloc(&i2c->dev, sizeof(*pdata), GFP_KERNEL);
		if (!pdata) {
			dev_err(&i2c->dev, "Failed to allocate memory\n");
			ret = -ENOMEM;
			goto err_dt_nomem;
		}
		ret = s2mu003mfd_parse_dt(&i2c->dev, pdata);
		if (ret < 0)
			goto err_parse_dt;
	} else {
		pdata = i2c->dev.platform_data;
	}

	chip = kzalloc(sizeof(*chip), GFP_KERNEL);
	if (chip ==  NULL) {
		dev_err(&i2c->dev, "Memory is not enough.\n");
		ret = -ENOMEM;
		goto err_mfd_nomem;
	}
	chip->dev = &i2c->dev;

	ret = i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA |
			I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_I2C_BLOCK);
	if (!ret) {
		ret = i2c_get_functionality(i2c->adapter);
		dev_err(chip->dev, "I2C functionality is not supported.\n");
		ret = -ENOSYS;
		goto err_i2cfunc_not_support;
	}

	chip->i2c_client = i2c;
	chip->pdata = pdata;

	/* if board-init had already assigned irq_base (>=0) ,
	no need to allocate it;
	assign -1 to let this driver allocate resource by itself*/
	if (pdata->irq_base < 0)
		pdata->irq_base = irq_alloc_descs(-1, 0, S2MU003_IRQS_NR, 0);
	if (pdata->irq_base < 0) {
		pr_err("%s:%s irq_alloc_descs Fail! ret(%d)\n",
				"s2mu003-mfd", __func__, pdata->irq_base);
		ret = -EINVAL;
		goto irq_base_err;
	} else {
		chip->irq_base = pdata->irq_base;
		pr_info("%s:%s irq_base = %d\n",
				"s2mu003-mfd", __func__, chip->irq_base);
	irq_domain_add_legacy(of_node, S2MU003_IRQS_NR, chip->irq_base, 0,
				&irq_domain_simple_ops, NULL);
	}

	i2c_set_clientdata(i2c, chip);
	mutex_init(&chip->io_lock);

	wake_lock_init(&(chip->irq_wake_lock), WAKE_LOCK_SUSPEND,
			"s2mu003mfd_wakelock");

	/* To disable MRST function should be
	finished before set any reg init-value*/
	data = s2mu003_reg_read(i2c, 0x47);
	pr_info("%s : Manual Reset Data = 0x%x", __func__, data);
	s2mu003_clr_bits(i2c, 0x47, 1<<3); /*Disable Manual Reset*/

	ret = s2mu003_init_irq(chip);

	if (ret < 0) {
		dev_err(chip->dev,
				"Error : can't initialize S2MU003 MFD irq\n");
		goto err_init_irq;
	}

#ifdef CONFIG_REGULATOR_S2MU003
	ret = mfd_add_devices(chip->dev, 0, &s2mu003_regulator_devs[0],
			ARRAY_SIZE(s2mu003_regulator_devs),
			NULL, chip->irq_base, NULL);
	if (ret < 0) {
		dev_err(chip->dev,
				"Error : can't add regulator\n");
		goto err_add_regulator_devs;
	}
#endif /*CONFIG_REGULATOR_S2MU003*/

#ifdef CONFIG_LEDS_S2MU003
	ret = mfd_add_devices(chip->dev, 0, &s2mu003_fled_devs[0],
			ARRAY_SIZE(s2mu003_fled_devs),
			NULL, chip->irq_base, NULL);
	if (ret < 0) {
		dev_err(chip->dev, "Failed : add FlashLED devices");
		goto err_add_fled_devs;
	}
#endif /*CONFIG_LEDS_S2MU003*/


#ifdef CONFIG_CHARGER_S2MU003
	ret = mfd_add_devices(chip->dev, 0, &s2mu003_charger_devs[0],
			ARRAY_SIZE(s2mu003_charger_devs),
			NULL, chip->irq_base, NULL);
	if (ret < 0) {
		dev_err(chip->dev, "Failed : add charger devices\n");
		goto err_add_chg_devs;
	}
#endif /*CONFIG_CHARGER_S2MU003*/

	device_init_wakeup(chip->dev, 1);
	enable_irq_wake(chip->irq);

	pr_info("%s : S2MU003 MFD Driver Fin probe\n", __func__);
	return ret;

#ifdef CONFIG_CHARGER_S2MU003
err_add_chg_devs:
#endif /*CONFIG_CHARGER_S2MU003*/

#ifdef CONFIG_LEDS_S2MU003
err_add_fled_devs:
#endif /*CONFIG_LEDS_S2MU003*/
	mfd_remove_devices(chip->dev);
#ifdef CONFIG_REGULATOR_S2MU003
err_add_regulator_devs:
#endif /*CONFIG_REGULATOR_S2MU003*/
err_init_irq:
	wake_lock_destroy(&(chip->irq_wake_lock));
	mutex_destroy(&chip->io_lock);
irq_base_err:
err_i2cfunc_not_support:
	kfree(chip);
err_mfd_nomem:
	if(pdata)
		kfree(pdata);
err_parse_dt:
err_dt_nomem:
	return ret;
}
Ejemplo n.º 2
0
static int ta_notification(struct notifier_block *nb,
		unsigned long action, void *data)
{
	muic_attached_dev_t attached_dev = *(muic_attached_dev_t *)data;
	u8 temp;
	int ret;
	struct s2mu003_led_data *led_data =
		container_of(nb, struct s2mu003_led_data, batt_nb);

	switch (action) {
	case MUIC_NOTIFY_CMD_DETACH:
	case MUIC_NOTIFY_CMD_LOGICALLY_DETACH:
		pr_info("%s : DETACH\n", __func__);
		if (!led_data->attach_ta)
			goto err;

		pr_info("%s : TA DETACH\n", __func__);
		ret = s2mu003_assign_bits(led_data->i2c,
			S2MU003_FLED_CTRL1, 0x80, 0x00);
		if (ret < 0)
			goto err;

		temp = s2mu003_reg_read(led_data->i2c,
				S2MU003_FLED_CH1_CTRL4);
		if ((temp & 0x0C) == 0x0C) {
			ret = s2mu003_assign_bits(led_data->i2c,
				S2MU003_FLED_CH1_CTRL4,
				S2MU003_TORCH_ENABLE_MASK,
				S2MU003_FLASH_TORCH_OFF);

			pr_info("%s : LED OFF\n", __func__);
			if (ret < 0)
				goto err;
			ret = s2mu003_assign_bits(led_data->i2c,
				S2MU003_FLED_CH1_CTRL4,
				S2MU003_TORCH_ENABLE_MASK,
				S2MU003_TORCH_ON_I2C);

			pr_info("%s : LED ON\n", __func__);
			if (ret < 0)
				goto err;
		}
		break;

	case MUIC_NOTIFY_CMD_ATTACH:
	case MUIC_NOTIFY_CMD_LOGICALLY_ATTACH:
		pr_info("%s : ATTACH", __func__);
		led_data->attach_ta = 0;
		attach_cable_check(attached_dev, &led_data->attach_ta);
		if (led_data->attach_ta) {
			ret = s2mu003_assign_bits(led_data->i2c,
				S2MU003_FLED_CTRL1, 0x80, 0x80);

			pr_info("%s : TA ATTACH\n", __func__);
			if (ret < 0)
				goto err;
		}
		return 0;
	default:
		goto err;
		break;
	}

	pr_info("%s : complete TA detached\n", __func__);
	return 0;
err:
	pr_err("%s : abandond access %d\n", __func__, led_data->attach_ta);
	return 0;
}