static bool isl29028_set_als_persist(struct i2c_client *client, bool is_enable,
			int persist)
{
	int prox_perstant[] = {1, 4, 8, 16};
	int i;
	int sel;
	bool st;
	if (is_enable) {
		for (i = 0; i < ARRAY_SIZE(prox_perstant) - 1; ++i) {
			if ((prox_perstant[i] <= persist) &&
						persist < prox_perstant[i+1])
				break;
		}
		sel = i;
	}

	if (is_enable) {
		dev_dbg(&client->dev, "Enabling als threshold interrupt\n");
		st = isl29028_write_data(client, ISL29028_REG_ADD_INTERRUPT,
			sel, INTERRUPT_ALS_PERSIST_MASK,
			INTERRUPT_ALS_PERSIST_SH);
		if (st)
			st = isl29028_write_data(client,
				ISL29028_REG_ADD_INTERRUPT,
				INTERRUPT_ALS_FLAG_EN,
				INTERRUPT_ALS_FLAG_MASK,
				INTERRUPT_ALS_FLAG_SH);
	} else {
		st = isl29028_write_data(client,
			ISL29028_REG_ADD_INTERRUPT, INTERRUPT_ALS_FLAG_DIS,
			INTERRUPT_ALS_FLAG_MASK, INTERRUPT_ALS_FLAG_SH);
	}
	return st;
}
static bool isl29028_set_proxim_period(struct i2c_client *client,
		bool is_enable,	int period)
{
	int prox_period[] = {0, 12, 50, 75, 100, 200, 400, 800};
	int i;
	int sel;
	bool st;
	if (period < 12)
		sel = 7;
	else {
		for (i = 1; i < ARRAY_SIZE(prox_period) - 1; ++i) {
			if ((prox_period[i] <= period) &&
						period < prox_period[i + 1])
				break;
		}
		sel = 7 - i;
	}

	if (!is_enable) {
		dev_dbg(&client->dev, "Disabling proximity sensing\n");
		st = isl29028_write_data(client, ISL29028_REG_ADD_CONFIGURE,
			0, CONFIGURE_PROX_EN_MASK, CONFIGURE_PROX_EN_SH);
	} else {
		dev_dbg(&client->dev, "Enabling proximity sensing with period "
			"of %d ms sel %d period %d\n", prox_period[7 - sel],
			sel, period);
		st = isl29028_write_data(client, ISL29028_REG_ADD_CONFIGURE,
			sel, CONFIGURE_PROX_SLP_MASK, CONFIGURE_PROX_SLP_SH);
		if (st)
			st = isl29028_write_data(client,
				ISL29028_REG_ADD_CONFIGURE, 1,
				CONFIGURE_PROX_EN_MASK, CONFIGURE_PROX_EN_SH);
	}
	return st;
}
static irqreturn_t threshold_isr(int irq, void *irq_data)
{
	struct isl29028_chip *chip = (struct isl29028_chip *)irq_data;
	s32 int_reg;
	struct i2c_client *client = chip->client;

	int_reg = i2c_smbus_read_byte_data(client, ISL29028_REG_ADD_INTERRUPT);
	if (int_reg < 0) {
		dev_err(&client->dev, "Error in reading register %d, error %d\n",
				ISL29028_REG_ADD_INTERRUPT, int_reg);
		return IRQ_HANDLED;
	}

	if (int_reg & INTERRUPT_PROX_FLAG_MASK) {
		/* Write 0 to clear */
		isl29028_write_data(client,
			ISL29028_REG_ADD_INTERRUPT, INTERRUPT_PROX_FLAG_DIS,
			INTERRUPT_PROX_FLAG_MASK, INTERRUPT_PROX_FLAG_SH);
		if (chip->is_proxim_int_waiting)
			complete(&chip->prox_completion);
	}

	if (int_reg & INTERRUPT_ALS_FLAG_MASK) {
		/* Write 0 to clear */
		isl29028_write_data(client,
			ISL29028_REG_ADD_INTERRUPT, INTERRUPT_ALS_FLAG_DIS,
			INTERRUPT_ALS_FLAG_MASK, INTERRUPT_ALS_FLAG_SH);
		if (chip->is_als_int_waiting)
			complete(&chip->als_completion);
	}

	return IRQ_HANDLED;
}
static bool isl29028_set_als_ir_mode(struct i2c_client *client, bool is_enable,
	bool is_als)
{
	struct iio_dev *indio_dev = i2c_get_clientdata(client);
	struct isl29028_chip *chip = iio_priv(indio_dev);
	bool st;
	if (is_enable) {
		if (is_als) {
			dev_dbg(&client->dev, "Enabling ALS mode\n");
			st = isl29028_write_data(client,
				ISL29028_REG_ADD_CONFIGURE,
				CONFIGURE_ALS_IR_MODE_ALS,
				CONFIGURE_ALS_IR_MODE_MASK,
				CONFIGURE_ALS_IR_MODE_SH);
			if (st)
				st = isl29028_write_data(client,
					ISL29028_REG_ADD_CONFIGURE,
					CONFIGURE_ALS_RANGE_HIGH_LUX,
					CONFIGURE_ALS_RANGE_MASK,
					CONFIGURE_ALS_RANGE_SH);
			if (st)
				st = isl29028_set_irals_high_threshold(client,
					chip->als_high_thres);
			if (st)
				st = isl29028_set_irals_low_threshold(client,
					chip->als_low_thres);
		} else {
			dev_dbg(&client->dev, "Enabling IR mode\n");
			st = isl29028_write_data(client,
				ISL29028_REG_ADD_CONFIGURE,
				CONFIGURE_ALS_IR_MODE_IR,
				CONFIGURE_ALS_IR_MODE_MASK,
				CONFIGURE_ALS_IR_MODE_SH);
			if (st)
				st = isl29028_set_irals_high_threshold(client,
					chip->ir_high_thres);
			if (st)
				st = isl29028_set_irals_low_threshold(client,
					chip->ir_low_thres);
		}
		if (st)
			st = isl29028_write_data(client,
				ISL29028_REG_ADD_CONFIGURE,
				CONFIGURE_ALS_EN,
				CONFIGURE_ALS_EN_MASK,
				CONFIGURE_ALS_EN_SH);
	} else {
		st = isl29028_write_data(client,
			ISL29028_REG_ADD_CONFIGURE,
			CONFIGURE_ALS_DIS,
			CONFIGURE_ALS_EN_MASK,
			CONFIGURE_ALS_EN_SH);
	}
	return st;
}
static int isl29028_chip_init(struct i2c_client *client)
{
	struct iio_dev *indio_dev = i2c_get_clientdata(client);
	struct isl29028_chip *chip = iio_priv(indio_dev);
	int i;
	bool st;

	for (i = 0; i < ARRAY_SIZE(chip->reg_cache); i++)
		chip->reg_cache[i] = 0;

	chip->is_prox_enable  = 0;
	chip->prox_low_thres = 0;
	chip->prox_high_thres = 0xFF;
	chip->prox_period = ISL29028_PROX_PERIOD;
	chip->prox_reading = 0;

	chip->als_low_thres = 0;
	chip->als_high_thres = 0xFFF;
	chip->als_range = 1;
	chip->als_reading = 0;
	chip->als_ir_mode = 0;

	chip->ir_high_thres = 0xFFF;
	chip->ir_low_thres = 0;
	chip->ir_reading = 0;

	chip->is_int_enable = false;
	chip->prox_persist = 1;
	chip->als_persist = 1;
	chip->is_proxim_int_waiting = false;
	chip->is_als_int_waiting = false;
	chip->shutdown_complete = 0;

	/* if regulator is not available, then proceed with i2c write or
	 * if regulator is turned on then proceed with i2c write
	 */
	if (chip->isl_reg && !regulator_is_enabled(chip->isl_reg))
		return 0;

	st = isl29028_write_data(client, ISL29028_REG_ADD_TEST1_MODE,
					0x0, 0xFF, 0);
	if (st)
		st = isl29028_write_data(client, ISL29028_REG_ADD_TEST2_MODE,
					0x0, 0xFF, 0);
	if (st)
		st = isl29028_write_data(client, ISL29028_REG_ADD_CONFIGURE,
					0x0, 0xFF, 0);
	if (st)
		msleep(1);
	if (!st) {
		dev_err(&client->dev, "%s(): fails\n", __func__);
		return -ENODEV;
	}
	return 0;
}
static int isl29028_chip_init(struct i2c_client *client)
{
	struct isl29028_chip *chip = i2c_get_clientdata(client);
	int i;
	bool st;

	for (i = 0; i < ARRAY_SIZE(chip->reg_cache); i++)
		chip->reg_cache[i] = 0;

	chip->is_prox_enable  = 0;
	chip->prox_low_thres = 0;
	chip->prox_high_thres = 0xFF;
	chip->prox_period = 0;
	chip->prox_reading = 0;

	chip->als_low_thres = 0;
	chip->als_high_thres = 0xFFF;
	chip->als_range = 1;
	chip->als_reading = 0;
	chip->als_ir_mode = 0;

	chip->ir_high_thres = 0xFFF;
	chip->ir_low_thres = 0;
	chip->ir_reading = 0;

	chip->is_int_enable = false;
	chip->prox_persist = 1;
	chip->als_persist = 1;
	chip->is_proxim_int_waiting = false;
	chip->is_als_int_waiting = false;

	st = isl29028_write_data(client, ISL29028_REG_ADD_TEST1_MODE,
					0x0, 0xFF, 0);
	if (st)
		st = isl29028_write_data(client, ISL29028_REG_ADD_TEST2_MODE,
					0x0, 0xFF, 0);
	if (st)
		st = isl29028_write_data(client, ISL29028_REG_ADD_CONFIGURE,
					0x0, 0xFF, 0);
	if (st)
		msleep(1);
	if (!st) {
		dev_err(&client->dev, "%s(): fails\n", __func__);
		return -ENODEV;
	}
	return 0;
}
static bool isl29028_set_irals_low_threshold(struct i2c_client *client, u32 als)
{
	bool st;
	st = isl29028_write_data(client,
		ISL29028_REG_ADD_ALSIR_LH_THRES, (als >> 8) & 0xF,
		0xF << ISL29028_REG_ADD_ALSIR_LH_THRES_L_SH,
		ISL29028_REG_ADD_ALSIR_LH_THRES_L_SH);
	if (st)
		st = isl29028_write_data(client,
			ISL29028_REG_ADD_ALSIR_LOW_THRES,
			als & 0xFF, 0xFF, 0);
	return st;
}
static int isl29028_suspend(struct device *dev)
{
	struct i2c_client *client = to_i2c_client(dev);
	struct iio_dev *indio_dev = i2c_get_clientdata(client);
	struct isl29028_chip *chip = iio_priv(indio_dev);

	dev_dbg(&client->dev, "%s()\n", __func__);
	mutex_lock(&chip->lock);
	/* if regulator is available and regulator is enabled by isl29028
	 * then disable it
	 */
	if (chip->isl_reg && (chip->is_prox_enable || chip->als_ir_mode))
		regulator_disable(chip->isl_reg);
	/* if regulator is still enabled, put the device into shutdown */
	if (chip->isl_reg && regulator_is_enabled(chip->isl_reg))
		isl29028_write_data(client, ISL29028_REG_ADD_CONFIGURE,
					0x0, 0xFF, 0);
	mutex_unlock(&chip->lock);
	return 0;
}
static bool isl29028_set_proxim_low_threshold(struct i2c_client *client, u8 th)
{
	return isl29028_write_data(client, ISL29028_REG_ADD_PROX_LOW_THRES,
		th, 0xFF, 0);
}