/*
 ****************************************************************************
 * - Device operation such as;
 *   probe, init/exit, remove
 ****************************************************************************
 */
static int __devinit lm3561_probe(struct i2c_client *client,
	  const struct i2c_device_id *id)
{
	struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
	struct lm3561_platform_data *pdata = client->dev.platform_data;
	struct lm3561_drv_data *data;
	int result;

	dev_dbg(&client->dev, "%s\n", __func__);

	if (!pdata) {
		dev_err(&client->dev,
			"%s(): failed during init",
				__func__);
		return -EINVAL;
	}

	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) {
		dev_err(&client->dev,
			"%s(): failed during i2c_check_functionality",
			__func__);
		return -EIO;
	}

	data = kzalloc(sizeof(*data), GFP_KERNEL);
	if (!data) {
		dev_err(&client->dev, "%s(): failed during kzalloc", __func__);
		return -ENOMEM;
	}

	dev_set_drvdata(&client->dev, data);
	data->client = client;
	data->led_nums = 1;
	data->torch_current_shift = 0;
	data->flash_current_shift = 0;
	if (pdata->current_limit >= 1500000) {
		data->reg_flash_duration_limit =
			LM3561_FLASH_DURATION_CL_1500MA;
	} else if (pdata->current_limit >= 1000000) {
		data->reg_flash_duration_limit =
			LM3561_FLASH_DURATION_CL_1000MA;
	} else {
		/* current_limit > 1500000uA || current_limit < 1000000uA */
		dev_err(&data->client->dev,
			"%s(): current_limit(%luuA) is invalid\n",
			__func__, pdata->current_limit);
		result = -EINVAL;
		goto err_init;
	}
	mutex_init(&data->lock);
	pm_runtime_enable(&client->dev);
	pm_suspend_ignore_children(&client->dev, true);
	result = pm_runtime_get_sync(&client->dev);
	if (result < 0)
		goto err_setup;
	result = lm3561_chip_init(data, pdata);
	if (result) {
		dev_err(&client->dev, "%s:chip init error\n", __func__);
		goto err_chip_init;
	}
	result = lm3561_create_sysfs_interfaces(&client->dev);
	if (result) {
		dev_err(&data->client->dev,
			"%s(): create sysfs failed",
				__func__);
		goto err_chip_init;
	}
	pm_runtime_set_autosuspend_delay(&client->dev, autosuspend_delay_ms);
	pm_runtime_use_autosuspend(&client->dev);
	pm_runtime_mark_last_busy(&data->client->dev);
	pm_runtime_put_autosuspend(&data->client->dev);
	dev_info(&data->client->dev, "%s: loaded\n", __func__);
	return 0;

err_chip_init:
	pm_runtime_suspend(&client->dev);
err_setup:
	pm_runtime_disable(&client->dev);
	if (pdata->platform_init)
		pdata->platform_init(&client->dev, 0);
err_init:
	dev_set_drvdata(&client->dev, NULL);
	kfree(data);
	dev_err(&client->dev,
		"%s: failed with code %d.\n", __func__, result);

	return result;
}
/*
 ****************************************************************************
 * - Device operation such as;
 *   probe, init/exit, remove
 ****************************************************************************
 */
static int __devinit lm3561_probe(struct i2c_client *client,
	  const struct i2c_device_id *id)
{
	struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
	struct lm3561_platform_data *pdata = client->dev.platform_data;
	struct lm3561_drv_data *data;
	int result;

	dev_info(&client->dev, "%s\n", __func__);

	if (!pdata) {
		dev_err(&data->client->dev,
			"%s(): failed during init",
				__func__);
		return -EINVAL;
	}

	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) {
		dev_err(&data->client->dev,
			"%s(): failed during i2c_check_functionality",
				__func__);
		return -EIO;
	}

	data = kzalloc(sizeof(*data), GFP_KERNEL);
	if (!data) {
		dev_err(&data->client->dev,
			"%s(): failed during kzalloc",
				__func__);
		return -ENOMEM;
	}

	dev_set_drvdata(&client->dev, data);

	data->client = client;

	result = pdata->hw_enable();
	if (result) {
		dev_err(&client->dev,
			"%s: Failed to HW Enable.\n", __func__);
		goto err_setup;
	}

	data->led_nums = 1;
	data->torch_current_shift = 0;
	data->flash_current_shift = 0;
	if (pdata->current_limit >= 1500000) {
		data->reg_flash_duration_limit =
			LM3561_FLASH_DURATION_CL_1500MA;
	} else if (pdata->current_limit >= 1000000) {
		data->reg_flash_duration_limit =
			LM3561_FLASH_DURATION_CL_1000MA;
	} else {
		/* current_limit > 1500000uA || current_limit < 1000000uA */
		dev_err(&data->client->dev,
			"%s(): current_limit(%luuA) is invalid\n",
			__func__, pdata->current_limit);
		result = -EINVAL;
		goto err_chip_init;
	}

	result = lm3561_chip_init(data, pdata);
	if (result) {
		dev_err(&data->client->dev,
			"%s(): chip init failed",
				__func__);
		goto err_chip_init;
	}

	result = lm3561_create_sysfs_interfaces(&client->dev);
	if (result) {
		dev_err(&data->client->dev,
			"%s(): create sysfs failed",
				__func__);
		goto err_chip_init;
	}

	dev_info(&data->client->dev, "%s: loaded\n", __func__);

	return 0;

err_chip_init:
	pdata->hw_disable();
err_setup:
	dev_set_drvdata(&client->dev, NULL);
	kfree(data);
	dev_err(&client->dev,
		"%s: failed with code %d.\n", __func__, result);

	return result;
}