/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
 * only version 2 as published by the Free Software Foundation.
 *
 * 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.
 */

#define pr_fmt(fmt) "%s: " fmt, __func__

#include <linux/bitrev.h>
#include <linux/crc-ccitt.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/workqueue.h>
#include <linux/bif/consumer.h>
#include <linux/bif/driver.h>

/**
 * struct bif_ctrl_dev - holds controller device specific information
 * @list:			Doubly-linked list parameter linking to other
 *				BIF controllers registered in the system
 * @desc:			Description structure for this BIF controller
 * @mutex:			Mutex lock that is used to ensure mutual
 *				exclusion between transactions performed on the
 *				BIF bus for this controller
 * @ctrl_dev:			Device pointer to the BIF controller device
 * @driver_data:		Private data used by the BIF controller
 * @selected_sdev:		Slave device that is currently selected on
 *				the BIF bus of this controller
 * @bus_change_notifier:	Head of a notifier list containing notifier
 *				blocks that are notified when the battery
 *				presence changes
 * @enter_irq_mode_work:	Work task that is scheduled after a transaction
 *				completes when there are consumers that are
 *				actively monitoring BIF slave interrupts
 * @irq_count:			This is a count of the total number of BIF slave
 *				interrupts that are currently being monitored
 *				for the BIF slaves connected to this BIF
 *				controller
 * @irq_mode_delay_jiffies:	Number of jiffies to wait before scheduling the
 *				enter IRQ mode task.  Using a larger value
 *				helps to improve the performance of BIF
 *				consumers that perform many BIF transactions.
 *				Using a smaller value reduces the latency of
 *				BIF slave interrupts.
 * @battery_present:		Cached value of the battery presence.  This is
 *				used to filter out spurious presence update
 *				calls when the battery presence state has not
 *				changed.
 */
struct bif_ctrl_dev {
	struct list_head		list;
	struct bif_ctrl_desc		*desc;
	struct mutex			mutex;
	struct device			*ctrl_dev;
	void				*driver_data;
	struct bif_slave_dev		*selected_sdev;
	struct blocking_notifier_head	bus_change_notifier;
	struct delayed_work		enter_irq_mode_work;
	int				irq_count;
	int				irq_mode_delay_jiffies;
	bool				battery_present;
};

/**
 * struct bif_ctrl - handle used by BIF consumers for bus oriented BIF
 *			operations
 * @bdev:		Pointer to BIF controller device
 * @exclusive_lock:	Flag which indicates that the BIF consumer responsible
 *			for this handle has locked the BIF bus of this
 *			controller.  BIF transactions from other consumers are
 *			blocked until the bus is unlocked.
 */
struct bif_ctrl {
	struct bif_ctrl_dev	*bdev;
	bool			exclusive_lock;
};

/**
 * struct bif_slave_dev - holds BIF slave device information
 * @list:			Doubly-linked list parameter linking to other
 *				BIF slaves that have been enumerated
 * @bdev:			Pointer to the BIF controller device that this
 *				slave is physically connected to
 * @slave_addr:			8-bit BIF DEV_ADR assigned to this slave
 * @unique_id:			80-bit BIF unique ID of the slave
 * @unique_id_bits_known:	Number of bits of the UID that are currently
 *				known.  This number starts is incremented during
 *				a UID search and must end at 80 if the slave
 *				responds to the search properly.
 * @present:			Boolean value showing if this slave is
*				physically present in the system at a given
*				point in time.  The value is set to false if the
*				battery pack containing the slave is
*				disconnected.
 * @l1_data:			BIF DDB L1 data of the slave as read from the
 *				slave's memory
 * @function_directory:		Pointer to the BIF DDB L2 function directory
 *				list as read from the slave's memory
 * @protocol_function:		Pointer to constant protocol function data as
 *				well as software state information if the slave
 *				has a protocol function
 * @slave_ctrl_function:	Pointer to constant slave control function data
 *				as well as software state information if the
 *				slave has a slave control function
 * @nvm_function:		Pointer to constant non-volatile memory function
 *				data as well as software state information if
 *				the slave has a non-volatile memory function
 *
 * bif_slave_dev objects are stored indefinitely after enumeration in order to
 * speed up battery reinsertion.  Only a UID check is needed after inserting a
 * battery assuming it has been enumerated before.
 *
 * unique_id bytes are stored such that unique_id[0] = MSB and
 * unique_id[BIF_UNIQUE_ID_BYTE_LENGTH - 1] = LSB
 */
struct bif_slave_dev {
	struct list_head			list;
	struct bif_ctrl_dev			*bdev;
	u8					slave_addr;
	u8				unique_id[BIF_UNIQUE_ID_BYTE_LENGTH];
	int					unique_id_bits_known;
	bool					present;
	struct bif_ddb_l1_data			l1_data;
	struct bif_ddb_l2_data			*function_directory;
	struct bif_protocol_function		*protocol_function;
	struct bif_slave_control_function	*slave_ctrl_function;
	struct bif_nvm_function			*nvm_function;
};

/**
 * struct bif_slave - handle used by BIF consumers for slave oriented BIF
 *			operations
 * @ctrl:		Consumer BIF controller handle data
 * @sdev:		Pointer to BIF slave device
 */
struct bif_slave {
	struct bif_ctrl				ctrl;
	struct bif_slave_dev			*sdev;
};

/* Number of times to retry a full BIF transaction before returning an error. */
#define BIF_TRANSACTION_RETRY_COUNT	5

static DEFINE_MUTEX(bif_ctrl_list_mutex);
static LIST_HEAD(bif_ctrl_list);
static DEFINE_MUTEX(bif_sdev_list_mutex);
static LIST_HEAD(bif_sdev_list);

static u8 next_dev_addr = 0x02;

#define DEBUG_PRINT_BUFFER_SIZE 256
static void fill_string(char *str, size_t str_len, u8 *buf, int buf_len)
{
	int pos = 0;
	int i;

	for (i = 0; i < buf_len; i++) {
		pos += scnprintf(str + pos, str_len - pos, "0x%02X", buf[i]);
		if (i < buf_len - 1)
			pos += scnprintf(str + pos, str_len - pos, ", ");
	}
}

static void bif_print_slave_data(struct bif_slave_dev *sdev)
{
	char str[DEBUG_PRINT_BUFFER_SIZE];
	u8 *uid;
	int i, j;
	struct bif_object *object;

	if (sdev->unique_id_bits_known != BIF_UNIQUE_ID_BIT_LENGTH)
		return;

	uid = sdev->unique_id;
	pr_debug("BIF slave: 0x%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X\n",
		uid[0], uid[1], uid[2], uid[3], uid[4], uid[5], uid[6],
		uid[7], uid[8], uid[9]);
	pr_debug("  present=%d, dev_adr=0x%02X\n", sdev->present,
		sdev->slave_addr);
	pr_debug("  revision=0x%02X, level=0x%02X, device class=0x%04X\n",
		sdev->l1_data.revision, sdev->l1_data.level,
		sdev->l1_data.device_class);
	pr_debug("  manufacturer ID=0x%04X, product ID=0x%04X\n",
		sdev->l1_data.manufacturer_id, sdev->l1_data.product_id);
	pr_debug("  function directory length=%d\n", sdev->l1_data.length);

	for (i = 0; i < sdev->l1_data.length / 4; i++) {
		pr_debug("  Function %d: type=0x%02X, version=0x%02X, pointer=0x%04X\n",
			i, sdev->function_directory[i].function_type,
			sdev->function_directory[i].function_version,
			sdev->function_directory[i].function_pointer);
	}

	if (sdev->nvm_function) {
		pr_debug("  NVM function: pointer=0x%04X, task=%d, wr_buf_size=%d, nvm_base=0x%04X, nvm_size=%d, nvm_lock_offset=%d\n",
			sdev->nvm_function->nvm_pointer,
			sdev->nvm_function->slave_control_channel,
			(sdev->nvm_function->write_buffer_size
				? sdev->nvm_function->write_buffer_size : 0),
			sdev->nvm_function->nvm_base_address,
			sdev->nvm_function->nvm_size,
			sdev->nvm_function->nvm_lock_offset);
		if (sdev->nvm_function->object_count)
			pr_debug("  NVM objects:\n");
		i = 0;
		list_for_each_entry(object, &sdev->nvm_function->object_list,
					list) {
			pr_debug("    Object %d - addr=0x%04X, data len=%d, type=0x%02X, version=0x%02X, manufacturer ID=0x%04X, crc=0x%04X\n",
				i, object->addr, object->length - 8,
				object->type, object->version,
				object->manufacturer_id, object->crc);
			for (j = 0; j < DIV_ROUND_UP(object->length - 8, 16);
					j++) {
				fill_string(str, DEBUG_PRINT_BUFFER_SIZE,
					object->data + j * 16,
					min(16, object->length - 8 - (j * 16)));
				pr_debug("      data(0x%04X): %s\n", j * 16,
					str);
			}
			i++;
		}
	}
}

static void bif_print_slaves(void)
{
	struct bif_slave_dev *sdev;

	mutex_lock(&bif_sdev_list_mutex);

	list_for_each_entry(sdev, &bif_sdev_list, list) {
		/* Skip slaves without fully known UIDs. */
		if (sdev->unique_id_bits_known != BIF_UNIQUE_ID_BIT_LENGTH)
			continue;
		bif_print_slave_data(sdev);
	}

	mutex_unlock(&bif_sdev_list_mutex);
}

static struct bif_slave_dev *bif_add_slave(struct bif_ctrl_dev *bdev)
{
	struct bif_slave_dev *sdev;

	sdev = kzalloc(sizeof(struct bif_slave_dev), GFP_KERNEL);
	if (sdev == NULL) {
		pr_err("Memory allocation failed for bif_slave_dev\n");
		return ERR_PTR(-ENOMEM);
	}

	sdev->bdev = bdev;
	INIT_LIST_HEAD(&sdev->list);
	list_add_tail(&sdev->list, &bif_sdev_list);

	return sdev;
}

static void bif_remove_slave(struct bif_slave_dev *sdev)
{
	list_del(&sdev->list);
	if (sdev->bdev->selected_sdev == sdev)
		sdev->bdev->selected_sdev = NULL;

	if (sdev->slave_ctrl_function)
		kfree(sdev->slave_ctrl_function->irq_notifier_list);
	kfree(sdev->slave_ctrl_function);
	kfree(sdev->protocol_function);
	kfree(sdev->function_directory);

	kfree(sdev);
}

/* This function assumes that the uid array is all 0 to start with. */
static void set_uid_bit(u8 uid[BIF_UNIQUE_ID_BYTE_LENGTH], unsigned int bit,
			unsigned int value)
{
	u8 mask;

	if (bit >= BIF_UNIQUE_ID_BIT_LENGTH)
		return;

	mask = 1 << (7 - (bit % 8));

	uid[bit / 8] &= ~mask;
	uid[bit / 8] |= value << (7 - (bit % 8));
}

static unsigned int get_uid_bit(u8 uid[BIF_UNIQUE_ID_BYTE_LENGTH],
			unsigned int bit)
{
	if (bit >= BIF_UNIQUE_ID_BIT_LENGTH)
		return 0;

	return (uid[bit / 8] & (1 << (7 - (bit % 8)))) ? 1 : 0;
}

static void bif_enter_irq_mode_work(struct work_struct *work)
{
	struct delayed_work *dwork = to_delayed_work(work);
	struct bif_ctrl_dev *bdev
		= container_of(dwork, struct bif_ctrl_dev, enter_irq_mode_work);
	int rc, i;

	mutex_lock(&bdev->mutex);
	for (i = 0; i < BIF_TRANSACTION_RETRY_COUNT; i++) {
		rc = bdev->desc->ops->set_bus_state(bdev,
					BIF_BUS_STATE_INTERRUPT);
		if (rc == 0)
			break;
	}
	mutex_unlock(&bdev->mutex);

	/* Reschedule the task if the transaction failed. */
	if (rc) {
		pr_err("Could not set BIF bus to interrupt mode, rc=%d\n", rc);
		schedule_delayed_work(&bdev->enter_irq_mode_work,
					bdev->irq_mode_delay_jiffies);
	}
}

static void bif_cancel_irq_mode_work(struct bif_ctrl_dev *bdev)
{
	cancel_delayed_work(&bdev->enter_irq_mode_work);
}

static void bif_schedule_irq_mode_work(struct bif_ctrl_dev *bdev)
{
	if (bdev->irq_count > 0 &&
	    bdev->desc->ops->get_bus_state(bdev) != BIF_BUS_STATE_INTERRUPT)
		schedule_delayed_work(&bdev->enter_irq_mode_work,
					bdev->irq_mode_delay_jiffies);
}

static int _bif_select_slave_no_retry(struct bif_slave_dev *sdev)
{
	struct bif_ctrl_dev *bdev = sdev->bdev;
	int rc = 0;
	int i;

	/* Check if the slave is already selected. */
	if (sdev->bdev->selected_sdev == sdev)
		return 0;

	if (sdev->slave_addr) {
		/* Select using DEV_ADR. */
		rc = bdev->desc->ops->bus_transaction(bdev, BIF_TRANS_SDA,
							sdev->slave_addr);
		if (!rc)
			sdev->bdev->selected_sdev = sdev;
	} else if (sdev->unique_id_bits_known == BIF_UNIQUE_ID_BIT_LENGTH) {
		/* Select using full UID. */
		for (i = 0; i < BIF_UNIQUE_ID_BYTE_LENGTH - 1; i++) {
			rc = bdev->desc->ops->bus_transaction(bdev,
				BIF_TRANS_EDA, sdev->unique_id[i]);
			if (rc)
				goto out;
		}

		rc = bdev->desc->ops->bus_transaction(bdev, BIF_TRANS_SDA,
			sdev->unique_id[BIF_UNIQUE_ID_BYTE_LENGTH - 1]);
		if (rc)
			goto out;
	} else {
		pr_err("Cannot select slave because it has neither UID nor DEV_ADR.\n");
		return -EINVAL;
	}

	sdev->bdev->selected_sdev = sdev;

	return 0;
out:
	pr_err("bus_transaction failed, rc=%d\n", rc);
	return rc;
}

static int bif_select_slave(struct bif_slave_dev *sdev)
{
	int rc = -EPERM;
	int i;

	for (i = 0; i < BIF_TRANSACTION_RETRY_COUNT; i++) {
		rc = _bif_select_slave_no_retry(sdev);
		if (rc == 0)
			break;
		/* Force slave reselection. */
		sdev->bdev->selected_sdev = NULL;
	}

	return rc;
}

/*
 * Returns 1 if slave is selected, 0 if slave is not selected, or errno if
 * error.
 */
static int bif_is_slave_selected(struct bif_ctrl_dev *bdev)
{
	int rc = -EPERM;
	int tack, i;

	for (i = 0; i < BIF_TRANSACTION_RETRY_COUNT; i++) {
		/* Attempt a transaction query. */
		rc = bdev->desc->ops->bus_transaction_read(bdev, BIF_TRANS_BC,
						BIF_CMD_TQ, &tack);
		if (rc == 0 || rc == -ETIMEDOUT)
			break;
	}

	if (rc == 0)
		rc = 1;
	else if (rc == -ETIMEDOUT)
		rc = 0;
	else
		pr_err("BIF bus_transaction_read failed, rc=%d\n", rc);

	return rc;
}

/* Read from a specified number of consecutive registers. */
static int _bif_slave_read_no_retry(struct bif_slave_dev *sdev, u16 addr,
			u8 *buf, int len)
{
	struct bif_ctrl_dev *bdev = sdev->bdev;
	int rc = 0;
	int i, response;

	rc = bif_select_slave(sdev);
	if (rc)
		return rc;

	if (bdev->desc->ops->read_slave_registers) {
		/*
		 * Use low level slave register read implementation in order to
		 * receive the benefits of BIF burst reads.
		 */
		rc = bdev->desc->ops->read_slave_registers(bdev, addr, buf,
							   len);
		if (rc)
			pr_debug("read_slave_registers failed, rc=%d\n", rc);
		else
			return rc;
		/*
		 * Fall back on individual transactions if high level register
		 * read failed.
		 */
	}

	for (i = 0; i < len; i++) {
		rc = bdev->desc->ops->bus_transaction(bdev, BIF_TRANS_ERA,
							addr >> 8);
		if (rc) {
			pr_err("bus_transaction failed, rc=%d\n", rc);
			return rc;
		}

		rc = bdev->desc->ops->bus_transaction_read(bdev, BIF_TRANS_RRA,
							addr & 0xFF, &response);
		if (rc) {
			pr_err("bus_transaction_read failed, rc=%d\n", rc);
			return rc;
		}

		if (!(response & BIF_SLAVE_RD_ACK)) {
			pr_err("BIF register read error=0x%02X\n",
				response & BIF_SLAVE_RD_ERR);
			return -EIO;
		}

		buf[i] = response & BIF_SLAVE_RD_DATA;
		addr++;
	}

	return rc;
}

/*
 * Read from a specified number of consecutive registers.  Retry the transaction
 * several times in case of communcation failures.
 */
static int _bif_slave_read(struct bif_slave_dev *sdev, u16 addr, u8 *buf,
			int len)
{
	int rc = -EPERM;
	int i;

	for (i = 0; i < BIF_TRANSACTION_RETRY_COUNT; i++) {
		rc = _bif_slave_read_no_retry(sdev, addr, buf, len);
		if (rc == 0)
			break;
		/* Force slave reselection. */
		sdev->bdev->selected_sdev = NULL;
	}

	return rc;
}

/* Write to a specified number of consecutive registers. */
static int _bif_slave_write_no_retry(struct bif_slave_dev *sdev, u16 addr,
			u8 *buf, int len)
{
	struct bif_ctrl_dev *bdev = sdev->bdev;
	int rc = 0;
	int i;

	rc = bif_select_slave(sdev);
	if (rc)
		return rc;

	if (bdev->desc->ops->write_slave_registers) {
		/*
		 * Use low level slave register write implementation in order to
		 * receive the benefits of BIF burst writes.
		 */
		rc = bdev->desc->ops->write_slave_registers(bdev, addr, buf,
							    len);
		if (rc)
			pr_debug("write_slave_registers failed, rc=%d\n", rc);
		else
			return rc;
		/*
		 * Fall back on individual transactions if high level register
		 * write failed.
		 */
	}

	rc = bdev->desc->ops->bus_transaction(bdev, BIF_TRANS_ERA, addr >> 8);
	if (rc)
		goto out;

	rc = bdev->desc->ops->bus_transaction(bdev, BIF_TRANS_WRA, addr & 0xFF);
	if (rc)
		goto out;

	for (i = 0; i < len; i++) {
		rc = bdev->desc->ops->bus_transaction(bdev, BIF_TRANS_WD,
							buf[i]);
		if (rc)
			goto out;
	}

	return 0;
out:
	pr_err("bus_transaction failed, rc=%d\n", rc);
	return rc;
}

/*
 * Write to a specified number of consecutive registers.  Retry the transaction
 * several times in case of communcation failures.
 */
static int _bif_slave_write(struct bif_slave_dev *sdev, u16 addr, u8 *buf,
			int len)
{
	int rc = -EPERM;
	int i;

	for (i = 0; i < BIF_TRANSACTION_RETRY_COUNT; i++) {
		rc = _bif_slave_write_no_retry(sdev, addr, buf, len);
		if (rc == 0)
			break;
		/* Force slave reselection. */
		sdev->bdev->selected_sdev = NULL;
	}

	return rc;
}

/* Perform a read-modify-write sequence on a single BIF slave register. */
static int _bif_slave_masked_write(struct bif_slave_dev *sdev, u16 addr, u8 val,
			u8 mask)
{
	int rc;
	u8 reg;

	rc = _bif_slave_read(sdev, addr, &reg, 1);
	if (rc)
		return rc;

	reg = (reg & ~mask) | (val & mask);

	return _bif_slave_write(sdev, addr, &reg, 1);
}

static int _bif_check_task(struct bif_slave_dev *sdev, unsigned int task)
{
	if (IS_ERR_OR_NULL(sdev)) {
		pr_err("Invalid slave device handle=%ld\n", PTR_ERR(sdev));
		return -EINVAL;
	} else if (!sdev->bdev) {
		pr_err("BIF controller has been removed\n");
		return -ENXIO;
	} else if (!sdev->slave_ctrl_function
			|| sdev->slave_ctrl_function->task_count == 0) {
		pr_err("BIF slave does not support slave control\n");
		return -ENODEV;
	} else if (task >= sdev->slave_ctrl_function->task_count) {
		pr_err("Requested task: %u greater than max: %u for this slave\n",
			task, sdev->slave_ctrl_function->task_count);
		return -EINVAL;
	}

	return 0;
}

static int _bif_task_is_busy(struct bif_slave_dev *sdev, unsigned int task)
{
	int rc;
	u16 addr;
	u8 reg = 0;

	rc = _bif_check_task(sdev, task);
	if (rc) {
		pr_err("Invalid slave device or task, rc=%d\n", rc);
		return rc;
	}

	/* Check the task busy state. */
	addr = SLAVE_CTRL_FUNC_TASK_BUSY_ADDR(
		sdev->slave_ctrl_function->slave_ctrl_pointer, task);
	rc = _bif_slave_read(sdev, addr, &reg, 1);
	if (rc) {
		pr_err("BIF slave register read failed, rc=%d\n", rc);
		return rc;
	}

	return (reg & BIT(task % SLAVE_CTRL_TASKS_PER_SET)) ? 1 : 0;
}

static int _bif_enable_auto_task(struct bif_slave_dev *sdev, unsigned int task)
{
	int rc;
	u16 addr;
	u8 mask;

	rc = _bif_check_task(sdev, task);
	if (rc) {
		pr_err("Invalid slave device or task, rc=%d\n", rc);
		return rc;
	}

	/* Enable the auto task within the slave */
	mask = BIT(task % SLAVE_CTRL_TASKS_PER_SET);
	addr = SLAVE_CTRL_FUNC_TASK_AUTO_TRIGGER_ADDR(
		sdev->slave_ctrl_function->slave_ctrl_pointer, task);
	if (task / SLAVE_CTRL_TASKS_PER_SET == 0) {
		/* Set global auto task enable. */
		mask |= BIT(0);
	}
	rc = _bif_slave_masked_write(sdev, addr, 0xFF, mask);
	if (rc) {
		pr_err("BIF slave register masked write failed, rc=%d\n", rc);
		return rc;
	}

	/* Set global auto task enable if task not in set 0. */
	if (task / SLAVE_CTRL_TASKS_PER_SET != 0) {
		addr = SLAVE_CTRL_FUNC_TASK_AUTO_TRIGGER_ADDR(
		       sdev->slave_ctrl_function->slave_ctrl_pointer, 0);
		rc = _bif_slave_masked_write(sdev, addr, 0xFF, BIT(0));
		if (rc) {
			pr_err("BIF slave register masked write failed, rc=%d\n",
				rc);
			return rc;
		}
	}

	return rc;
}

static int _bif_disable_auto_task(struct bif_slave_dev *sdev, unsigned int task)
{
	int rc;
	u16 addr;
	u8 mask;

	rc = _bif_check_task(sdev, task);
	if (rc) {
		pr_err("Invalid slave or task, rc=%d\n", rc);
		return rc;
	}

	/* Disable the auto task within the slave */
	mask = BIT(task % SLAVE_CTRL_TASKS_PER_SET);
	addr = SLAVE_CTRL_FUNC_TASK_AUTO_TRIGGER_ADDR(
		sdev->slave_ctrl_function->slave_ctrl_pointer, task);
	rc = _bif_slave_masked_write(sdev, addr, 0x00, mask);
	if (rc) {
		pr_err("BIF slave register masked write failed, rc=%d\n", rc);
		return rc;
	}

	return rc;
}

/*
 * The MIPI-BIF spec does not define a maximum time in which an NVM write must
 * complete.  The following delay and recheck count therefore represent
 * arbitrary but reasonable values.
 */
#define NVM_WRITE_POLL_DELAY_MS		20
#define NVM_WRITE_MAX_POLL_COUNT	50

static int _bif_slave_nvm_raw_write(struct bif_slave_dev *sdev, u16 offset,
				u8 *buf, int len)
{
	int rc = 0;
	int write_len, poll_count, rc2;
	u8 write_buf[3];

	if (!sdev->nvm_function) {
		pr_err("BIF slave has no NVM function\n");
		return -ENODEV;
	} else if (offset + len > sdev->nvm_function->nvm_size) {
		pr_err("write offset + len = %d > NVM size = %d\n",
			offset + len, sdev->nvm_function->nvm_size);
		return -EINVAL;
	} else if (offset < sdev->nvm_function->nvm_lock_offset) {
		pr_err("write offset = %d < first writable offset = %d\n",
			offset, sdev->nvm_function->nvm_lock_offset);
		return -EINVAL;
	}

	rc = _bif_enable_auto_task(sdev,
			sdev->nvm_function->slave_control_channel);
	if (rc) {
		pr_err("Failed to enable NVM auto task, rc=%d\n", rc);
		return rc;
	}

	while (len > 0) {
		write_len = sdev->nvm_function->write_buffer_size;
		if (write_len == 0)
			write_len = 256;
		write_len = min(write_len, len);

		write_buf[0] = offset >> 8;
		write_buf[1] = offset;
		write_buf[2] = (write_len == 256) ? 0 : write_len;

		/* Write offset and size registers. */
		rc = _bif_slave_write(sdev, sdev->nvm_function->nvm_pointer + 6,
					write_buf, 3);
		if (rc) {
			pr_err("BIF slave write failed, rc=%d\n", rc);
			goto done;
		}

		/* Write to NVM write buffer registers. */
		rc = _bif_slave_write(sdev, sdev->nvm_function->nvm_pointer + 9,
					buf, write_len);
		if (rc) {
			pr_err("BIF slave write failed, rc=%d\n", rc);
			goto done;
		}

		/*
		 * Wait for completion of the NVM write which was auto-triggered
		 * by the register write of the last byte in the NVM write
		 * buffer.
		 */
		poll_count = NVM_WRITE_MAX_POLL_COUNT;
		do {
			msleep(NVM_WRITE_POLL_DELAY_MS);
			rc = _bif_task_is_busy(sdev,
				sdev->nvm_function->slave_control_channel);
			poll_count--;
		} while (rc > 0 && poll_count > 0);

		if (rc < 0) {
			pr_err("Failed to check task state, rc=%d", rc);
			goto done;
		} else if (rc > 0) {
			pr_err("BIF slave NVM write not completed after %d ms\n",
			    NVM_WRITE_POLL_DELAY_MS * NVM_WRITE_MAX_POLL_COUNT);
			rc = -ETIMEDOUT;
			goto done;
		}

		len -= write_len;
		offset += write_len;
		buf += write_len;
	}

done:
	rc2 = _bif_disable_auto_task(sdev,
			sdev->nvm_function->slave_control_channel);
	if (rc2) {
		pr_err("Failed to disable NVM auto task, rc=%d\n", rc2);
		return rc2;
	}

	return rc;
}

/* Takes a mutex if this consumer is not an exclusive bus user. */
static void bif_ctrl_lock(struct bif_ctrl *ctrl)
{
	if (!ctrl->exclusive_lock) {
		mutex_lock(&ctrl->bdev->mutex);
		bif_cancel_irq_mode_work(ctrl->bdev);
	}
}

/* Releases a mutex if this consumer is not an exclusive bus user. */
static void bif_ctrl_unlock(struct bif_ctrl *ctrl)
{
	if (!ctrl->exclusive_lock) {
		bif_schedule_irq_mode_work(ctrl->bdev);
		mutex_unlock(&ctrl->bdev->mutex);
	}
}

static void bif_slave_ctrl_lock(struct bif_slave *slave)
{
	bif_ctrl_lock(&slave->ctrl);
}

static void bif_slave_ctrl_unlock(struct bif_slave *slave)
{
	bif_ctrl_unlock(&slave->ctrl);
}

/**
 * bif_crc_ccitt() - calculate the CRC-CCITT CRC value of the data specified
 * @buffer:	Data to calculate the CRC of
 * @len:	Length of the data buffer in bytes
 *
 * MIPI-BIF specifies the usage of CRC-CCITT for BIF data objects.  This
 * function performs the CRC calculation while taking into account the bit
 * ordering used by BIF.
 */
u16 bif_crc_ccitt(const u8 *buffer, unsigned int len)
{
	u16 crc = 0xFFFF;

	while (len--) {
		crc = crc_ccitt_byte(crc, bitrev8(*buffer));
		buffer++;
	}
	return bitrev16(crc);
}
EXPORT_SYMBOL(bif_crc_ccitt);

static u16 bif_object_crc_ccitt(const struct bif_object *object)
{
	u16 crc = 0xFFFF;
	int i;

	crc = crc_ccitt_byte(crc, bitrev8(object->type));
	crc = crc_ccitt_byte(crc, bitrev8(object->version));
	crc = crc_ccitt_byte(crc, bitrev8(object->manufacturer_id >> 8));
	crc = crc_ccitt_byte(crc, bitrev8(object->manufacturer_id));
	crc = crc_ccitt_byte(crc, bitrev8(object->length >> 8));
	crc = crc_ccitt_byte(crc, bitrev8(object->length));

	for (i = 0; i < object->length - 8; i++)
		crc = crc_ccitt_byte(crc, bitrev8(object->data[i]));

	return bitrev16(crc);
}

static int bif_check_task(struct bif_slave *slave, unsigned int task)
{
	if (IS_ERR_OR_NULL(slave)) {
		pr_err("Invalid slave pointer=%ld\n", PTR_ERR(slave));
		return -EINVAL;
	}

	return _bif_check_task(slave->sdev, task);
}

/**
 * bif_request_irq() - request a BIF slave IRQ by slave task number
 * @slave:	BIF slave handle
 * @task:	BIF task number of the IRQ inside of the slave.  This
 *		corresponds to the slave control channel specified for a given
 *		BIF function inside of the slave.
 * @nb:		Notifier block to call when the IRQ fires
 *
 * This function registers a notifier block to call when the BIF slave interrupt
 * is triggered and also enables the interrupt.  The interrupt is enabled inside
 * of the BIF slave's slave control function and also the BIF bus is put into
 * interrupt mode.
 *
 * Returns 0 for success or errno if an error occurred.
 */
int bif_request_irq(struct bif_slave *slave, unsigned int task,
			struct notifier_block *nb)
{
	int rc;
	u16 addr;
	u8 reg, mask;

	rc = bif_check_task(slave, task);
	if (rc) {
		pr_err("Invalid slave or task, rc=%d\n", rc);
		return rc;
	}

	bif_slave_ctrl_lock(slave);

	rc = blocking_notifier_chain_register(
		&slave->sdev->slave_ctrl_function->irq_notifier_list[task], nb);
	if (rc) {
		pr_err("Notifier registration failed, rc=%d\n", rc);
		goto done;
	}

	/* Enable the interrupt within the slave */
	mask = BIT(task % SLAVE_CTRL_TASKS_PER_SET);
	addr = SLAVE_CTRL_FUNC_IRQ_EN_ADDR(
		slave->sdev->slave_ctrl_function->slave_ctrl_pointer, task);
	if (task / SLAVE_CTRL_TASKS_PER_SET == 0) {
		/* Set global interrupt enable. */
		mask |= BIT(0);
	}
	rc = _bif_slave_read(slave->sdev, addr, &reg, 1);
	if (rc) {
		pr_err("BIF slave register read failed, rc=%d\n", rc);
		goto notifier_unregister;
	}
	reg |= mask;
	rc = _bif_slave_write(slave->sdev, addr, &reg, 1);
	if (rc) {
		pr_err("BIF slave register write failed, rc=%d\n", rc);
		goto notifier_unregister;
	}

	/* Set global interrupt enable if task not in set 0. */
	if (task / SLAVE_CTRL_TASKS_PER_SET != 0) {
		mask = BIT(0);
		addr = SLAVE_CTRL_FUNC_IRQ_EN_ADDR(
		       slave->sdev->slave_ctrl_function->slave_ctrl_pointer, 0);
		rc = _bif_slave_read(slave->sdev, addr, &reg, 1);
		if (rc) {
			pr_err("BIF slave register read failed, rc=%d\n", rc);
			goto notifier_unregister;
		}
		reg |= mask;
		rc = _bif_slave_write(slave->sdev, addr, &reg, 1);
		if (rc) {
			pr_err("BIF slave register write failed, rc=%d\n", rc);
			goto notifier_unregister;
		}
	}

	rc = slave->sdev->bdev->desc->ops->set_bus_state(slave->sdev->bdev,
		BIF_BUS_STATE_INTERRUPT);
	if (rc) {
		pr_err("Could not set BIF bus to interrupt mode, rc=%d\n", rc);
		goto notifier_unregister;
	}

	slave->sdev->bdev->irq_count++;
done:
	bif_slave_ctrl_unlock(slave);

	return rc;

notifier_unregister:
	blocking_notifier_chain_unregister(
		&slave->sdev->slave_ctrl_function->irq_notifier_list[task],
		nb);
	bif_slave_ctrl_unlock(slave);

	return rc;

}
EXPORT_SYMBOL(bif_request_irq);

/**
 * bif_free_irq() - free a BIF slave IRQ by slave task number
 * @slave:	BIF slave handle
 * @task:	BIF task number of the IRQ inside of the slave.  This
 *		corresponds to the slave control channel specified for a given
 *		BIF function inside of the slave.
 * @nb:		Notifier block previously registered with this interrupt
 *
 * This function unregisters a notifier block that was previously registered
 * with bif_request_irq().
 *
 * Returns 0 for success or errno if an error occurred.
 */
int bif_free_irq(struct bif_slave *slave, unsigned int task,
			struct notifier_block *nb)
{
	int rc;
	u16 addr;
	u8 reg;

	rc = bif_check_task(slave, task);
	if (rc) {
		pr_err("Invalid slave or task, rc=%d\n", rc);
		return rc;
	}

	bif_slave_ctrl_lock(slave);

	/* Disable the interrupt within the slave */
	reg = BIT(task % SLAVE_CTRL_TASKS_PER_SET);
	addr = SLAVE_CTRL_FUNC_IRQ_CLEAR_ADDR(
		slave->sdev->slave_ctrl_function->slave_ctrl_pointer, task);
	rc = _bif_slave_write(slave->sdev, addr, &reg, 1);
	if (rc) {
		pr_err("BIF slave register write failed, rc=%d\n", rc);
		goto done;
	}

	rc = blocking_notifier_chain_unregister(
		&slave->sdev->slave_ctrl_function->irq_notifier_list[task], nb);
	if (rc) {
		pr_err("Notifier unregistration failed, rc=%d\n", rc);
		goto done;
	}

	slave->sdev->bdev->irq_count--;

	if (slave->sdev->bdev->irq_count == 0) {
		bif_cancel_irq_mode_work(slave->sdev->bdev);
	} else if (slave->sdev->bdev->irq_count < 0) {
		pr_err("Unbalanced IRQ free.\n");
		rc = -EINVAL;
		slave->sdev->bdev->irq_count = 0;
	}
done:
	bif_slave_ctrl_unlock(slave);

	return rc;
}
EXPORT_SYMBOL(bif_free_irq);

/**
 * bif_trigger_task() - trigger a task within a BIF slave
 * @slave:	BIF slave handle
 * @task:	BIF task inside of the slave to trigger.  This corresponds to
 *		the slave control channel specified for a given BIF function
 *		inside of the slave.
 *
 * Returns 0 for success or errno if an error occurred.
 */
int bif_trigger_task(struct bif_slave *slave, unsigned int task)
{
	int rc;
	u16 addr;
	u8 reg;

	rc = bif_check_task(slave, task);
	if (rc) {
		pr_err("Invalid slave or task, rc=%d\n", rc);
		return rc;
	}

	bif_slave_ctrl_lock(slave);

	/* Trigger the task within the slave. */
	reg = BIT(task % SLAVE_CTRL_TASKS_PER_SET);
	addr = SLAVE_CTRL_FUNC_TASK_TRIGGER_ADDR(
		slave->sdev->slave_ctrl_function->slave_ctrl_pointer, task);
	rc = _bif_slave_write(slave->sdev, addr, &reg, 1);
	if (rc) {
		pr_err("BIF slave register write failed, rc=%d\n", rc);
		goto done;
	}

done:
	bif_slave_ctrl_unlock(slave);

	return rc;
}
EXPORT_SYMBOL(bif_trigger_task);

/**
 * bif_enable_auto_task() - enable task auto triggering for the specified task
 * @slave:	BIF slave handle
 * @task:	BIF task inside of the slave to configure for automatic
 *		triggering.  This corresponds to the slave control channel
 *		specified for a given BIF function inside of the slave.
 *
 * Returns 0 for success or errno if an error occurred.
 */
int bif_enable_auto_task(struct bif_slave *slave, unsigned int task)
{
	int rc;

	if (IS_ERR_OR_NULL(slave)) {
		pr_err("Invalid slave pointer=%ld\n", PTR_ERR(slave));
		return -EINVAL;
	}

	bif_slave_ctrl_lock(slave);
	rc = _bif_enable_auto_task(slave->sdev, task);
	bif_slave_ctrl_unlock(slave);

	return rc;
}
EXPORT_SYMBOL(bif_enable_auto_task);

/**
 * bif_disable_auto_task() - disable task auto triggering for the specified task
 * @slave:	BIF slave handle
 * @task:	BIF task inside of the slave to stop automatic triggering on.
 *		This corresponds to the slave control channel specified for a
 *		given BIF function inside of the slave.
 *
 * This function should be called after bif_enable_auto_task() in a paired
 * fashion.
 *
 * Returns 0 for success or errno if an error occurred.
 */
int bif_disable_auto_task(struct bif_slave *slave, unsigned int task)
{
	int rc;

	if (IS_ERR_OR_NULL(slave)) {
		pr_err("Invalid slave pointer=%ld\n", PTR_ERR(slave));
		return -EINVAL;
	}

	bif_slave_ctrl_lock(slave);
	rc = _bif_disable_auto_task(slave->sdev, task);
	bif_slave_ctrl_unlock(slave);

	return rc;
}
EXPORT_SYMBOL(bif_disable_auto_task);

/**
 * bif_task_is_busy() - checks the state of a BIF slave task
 * @slave:	BIF slave handle
 * @task:	BIF task inside of the slave to trigger.  This corresponds to
 *		the slave control channel specified for a given	BIF function
 *		inside of the slave.
 *
 * Returns 1 if the task is busy, 0 if it is not busy, and errno on error.
 */
int bif_task_is_busy(struct bif_slave *slave, unsigned int task)
{
	int rc;

	if (IS_ERR_OR_NULL(slave)) {
		pr_err("Invalid slave pointer=%ld\n", PTR_ERR(slave));
		return -EINVAL;
	}

	bif_slave_ctrl_lock(slave);
	rc = _bif_task_is_busy(slave->sdev, task);
	bif_slave_ctrl_unlock(slave);

	return rc;
}
EXPORT_SYMBOL(bif_task_is_busy);

static int bif_slave_notify_irqs(struct bif_slave_dev *sdev, int set, u8 val)
{
	int rc = 0;
	int i, task;

	for (i = 0; i < SLAVE_CTRL_TASKS_PER_SET; i++) {
		if (val & (1 << i)) {
			task = set * SLAVE_CTRL_TASKS_PER_SET + i;

			rc = blocking_notifier_call_chain(
			    &sdev->slave_ctrl_function->irq_notifier_list[task],
			    task, sdev->bdev);
			rc = notifier_to_errno(rc);
			if (rc)
				pr_err("Notification failed for task %d\n",
					task);
		}
	}

	return rc;
}

static int bif_slave_handle_irq(struct bif_slave_dev *sdev)
{
	struct bif_ctrl_dev *bdev = sdev->bdev;
	bool resp = false;
	int rc = 0;
	int i;
	u16 addr;
	u8 reg;

	mutex_lock(&sdev->bdev->mutex);
	bif_cancel_irq_mode_work(sdev->bdev);

	rc = bif_select_slave(sdev);
	if (rc) {
		pr_err("Could not select slave, rc=%d\n", rc);
		goto done;
	}

	/* Check overall slave interrupt status. */
	rc = bdev->desc->ops->bus_transaction_query(bdev, BIF_TRANS_BC,
						    BIF_CMD_ISTS, &resp);
	if (rc) {
		pr_err("Could not query slave interrupt status, rc=%d\n", rc);
		goto done;
	}

	if (resp) {
		for (i = 0; i < sdev->slave_ctrl_function->task_count
					/ SLAVE_CTRL_TASKS_PER_SET; i++) {
			addr = sdev->slave_ctrl_function->slave_ctrl_pointer
				+ 4 * i + 1;
			rc = _bif_slave_read(sdev, addr, &reg, 1);
			if (rc) {
				pr_err("BIF slave register read failed, rc=%d\n",
					rc);
				goto done;
			}

			/* Ensure that interrupts are pending in the set. */
			if (reg != 0x00) {
				/*
				 * Release mutex before notifying consumers so
				 * that they can use the bus.
				 */
				mutex_unlock(&sdev->bdev->mutex);
				rc = bif_slave_notify_irqs(sdev, i, reg);
				if (rc) {
					pr_err("BIF slave irq notification failed, rc=%d\n",
						rc);
					goto notification_failed;
				}
				mutex_lock(&sdev->bdev->mutex);

				rc = bif_select_slave(sdev);
				if (rc) {
					pr_err("Could not select slave, rc=%d\n",
						rc);
					goto done;
				}

				/* Clear all interrupts in this set. */
				rc = _bif_slave_write(sdev, addr, &reg, 1);
				if (rc) {
					pr_err("BIF slave register write failed, rc=%d\n",
						rc);
					goto done;
				}
			}
		}
	}

done:
	bif_schedule_irq_mode_work(sdev->bdev);
	mutex_unlock(&sdev->bdev->mutex);
notification_failed:
	if (rc == 0)
		rc = resp;
	return rc;
}

/**
 * bif_ctrl_notify_slave_irq() - notify the BIF framework that a slave interrupt
 *				was received by a BIF controller
 * @bdev:	BIF controller device pointer
 *
 * This function should only be called from a BIF controller driver.
 *
 * Returns 0 for success or errno if an error occurred.
 */
int bif_ctrl_notify_slave_irq(struct bif_ctrl_dev *bdev)
{
	struct bif_slave_dev *sdev;
	int rc = 0, handled = 0;

	if (IS_ERR_OR_NULL(bdev))
		return -EINVAL;

	mutex_lock(&bif_sdev_list_mutex);

	list_for_each_entry(sdev, &bif_sdev_list, list) {
		if (sdev->bdev == bdev && sdev->present) {
			rc = bif_slave_handle_irq(sdev);
			if (rc < 0) {
				pr_err("Could not handle BIF slave irq, rc=%d\n",
					rc);
				break;
			}
			handled += rc;
		}
	}

	mutex_unlock(&bif_sdev_list_mutex);

	if (handled == 0)
		pr_info("Spurious BIF slave interrupt detected.\n");

	if (rc > 0)
		rc = 0;

	return rc;
}
EXPORT_SYMBOL(bif_ctrl_notify_slave_irq);

/**
 * bif_ctrl_notify_battery_changed() - notify the BIF framework that a battery
 *				pack has been inserted or removed
 * @bdev:	BIF controller device pointer
 *
 * This function should only be called from a BIF controller driver.
 *
 * Returns 0 for success or errno if an error occurred.
 */
int bif_ctrl_notify_battery_changed(struct bif_ctrl_dev *bdev)
{
	int rc = 0;
	int present;

	if (IS_ERR_OR_NULL(bdev))
		return -EINVAL;

	if (bdev->desc->ops->get_battery_presence) {
		present = bdev->desc->ops->get_battery_presence(bdev);
		if (present < 0) {
			pr_err("Could not determine battery presence, rc=%d\n",
				rc);
			return rc;
		}

		if (bdev->battery_present == !!present)
			return 0;

		bdev->battery_present = present;

		rc = blocking_notifier_call_chain(&bdev->bus_change_notifier,
			present ? BIF_BUS_EVENT_BATTERY_INSERTED
				: BIF_BUS_EVENT_BATTERY_REMOVED, bdev);
		if (rc)
			pr_err("Call chain noification failed, rc=%d\n", rc);
	}

	return rc;
}
EXPORT_SYMBOL(bif_ctrl_notify_battery_changed);

/**
 * bif_ctrl_signal_battery_changed() - notify the BIF framework that a battery
 *				pack has been inserted or removed
 * @ctrl:	BIF controller consumer handle
 *
 * This function should only be called by a BIF consumer driver on systems where
 * the BIF controller driver is unable to determine when a battery is inserted
 * or removed.
 *
 * Returns 0 for success or errno if an error occurred.
 */
int bif_ctrl_signal_battery_changed(struct bif_ctrl *ctrl)
{
	if (IS_ERR_OR_NULL(ctrl))
		return -EINVAL;

	return bif_ctrl_notify_battery_changed(ctrl->bdev);
}
EXPORT_SYMBOL(bif_ctrl_signal_battery_changed);

/**
 * bif_ctrl_notifier_register() - register a notifier block to be called when
 *				a battery pack is inserted or removed
 * @ctrl:	BIF controller consumer handle
 *
 * The value passed into the notifier when it is called is one of
 * enum bif_bus_event.
 *
 * Returns 0 for success or errno if an error occurred.
 */
int bif_ctrl_notifier_register(struct bif_ctrl *ctrl, struct notifier_block *nb)
{
	int rc;

	if (IS_ERR_OR_NULL(ctrl))
		return -EINVAL;

	rc = blocking_notifier_chain_register(&ctrl->bdev->bus_change_notifier,
					      nb);
	if (rc)
		pr_err("Notifier registration failed, rc=%d\n", rc);

	return rc;
}
EXPORT_SYMBOL(bif_ctrl_notifier_register);

/**
 * bif_ctrl_notifier_unregister() - unregister a battery status change notifier
 *				block that was previously registered
 * @ctrl:	BIF controller consumer handle
 *
 * Returns 0 for success or errno if an error occurred.
 */
int bif_ctrl_notifier_unregister(struct bif_ctrl *ctrl,
				 struct notifier_block *nb)
{
	int rc;

	if (IS_ERR_OR_NULL(ctrl))
		return -EINVAL;

	rc =
	    blocking_notifier_chain_unregister(&ctrl->bdev->bus_change_notifier,
						nb);
	if (rc)
		pr_err("Notifier unregistration failed, rc=%d\n", rc);

	return rc;
}
EXPORT_SYMBOL(bif_ctrl_notifier_unregister);

/**
 * bif_get_bus_handle() - returns the BIF controller consumer handle associated
 *			with a BIF slave handle
 * @slave:	BIF slave handle
 *
 * Note, bif_ctrl_put() should never be called for the pointer output by
 * bif_get_bus_handle().
 */
struct bif_ctrl *bif_get_bus_handle(struct bif_slave *slave)
{
	if (IS_ERR_OR_NULL(slave))
		return ERR_PTR(-EINVAL);

	return &slave->ctrl;
}
EXPORT_SYMBOL(bif_get_bus_handle);

/**
 * bif_ctrl_count() - returns the number of registered BIF controllers
 */
int bif_ctrl_count(void)
{
	struct bif_ctrl_dev *bdev;
	int count = 0;

	mutex_lock(&bif_ctrl_list_mutex);

	list_for_each_entry(bdev, &bif_ctrl_list, list) {
		count++;
	}
	mutex_unlock(&bif_ctrl_list_mutex);

	return count;
}
EXPORT_SYMBOL(bif_ctrl_count);

/**
 * bif_ctrl_get_by_id() - get a handle for the id'th BIF controller registered
 *			in the system
 * @id:	Arbitrary number associated with the BIF bus in the system
 *
 * id must be in the range [0, bif_ctrl_count() - 1].  This function should only
 * need to be called by a BIF consumer that is unable to link to a given BIF
 * controller via a device tree binding.
 *
 * Returns a BIF controller consumer handle if successful or an ERR_PTR if not.
 */
struct bif_ctrl *bif_ctrl_get_by_id(unsigned int id)
{
	struct bif_ctrl_dev *bdev;
	struct bif_ctrl_dev *bdev_found = NULL;
	struct bif_ctrl *ctrl = ERR_PTR(-ENODEV);

	mutex_lock(&bif_ctrl_list_mutex);

	list_for_each_entry(bdev, &bif_ctrl_list, list) {
		if (id == 0) {
			bdev_found = bdev;
			break;
		}
		id--;
	}
	mutex_unlock(&bif_ctrl_list_mutex);

	if (bdev_found) {
		ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
		if (!ctrl) {
			pr_err("Bus handle allocation failed\n");
			ctrl = ERR_PTR(-ENOMEM);
		} else {
			ctrl->bdev = bdev_found;
		}
	}

	return ctrl;
}
EXPORT_SYMBOL(bif_ctrl_get_by_id);

/**
 * bif_ctrl_get() - get a handle for the BIF controller that is linked to the
 *			consumer device in the device tree
 * @consumer_dev:	Pointer to the consumer's device
 *
 * In order to use this function, the BIF consumer's device must specify the
 * "qcom,bif-ctrl" property in its device tree node which points to a BIF
 * controller device node.
 *
 * Returns a BIF controller consumer handle if successful or an ERR_PTR if not.
 * If the BIF controller linked to the consumer device has not yet probed, then
 * ERR_PTR(-EPROBE_DEFER) is returned.
 */
struct bif_ctrl *bif_ctrl_get(struct device *consumer_dev)
{
	struct device_node *ctrl_node = NULL;
	struct bif_ctrl_dev *bdev_found = NULL;
	struct bif_ctrl *ctrl = ERR_PTR(-EPROBE_DEFER);
	struct bif_ctrl_dev *bdev = NULL;

	if (!consumer_dev || !consumer_dev->of_node) {
		pr_err("Invalid device node\n");
		return ERR_PTR(-EINVAL);
	}

	ctrl_node = of_parse_phandle(consumer_dev->of_node, "qcom,bif-ctrl", 0);
	if (!ctrl_node) {
		pr_err("Could not find qcom,bif-ctrl property in %s\n",
			consumer_dev->of_node->full_name);
		return ERR_PTR(-ENXIO);
	}

	mutex_lock(&bif_ctrl_list_mutex);
	list_for_each_entry(bdev, &bif_ctrl_list, list) {
		if (bdev->ctrl_dev && bdev->ctrl_dev->of_node == ctrl_node) {
			bdev_found = bdev;
			break;
		}
	}
	mutex_unlock(&bif_ctrl_list_mutex);

	if (bdev_found) {
		ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
		if (!ctrl) {
			pr_err("Bus handle allocation failed\n");
			ctrl = ERR_PTR(-ENOMEM);
		} else {
			ctrl->bdev = bdev_found;
		}
	}

	return ctrl;
}
EXPORT_SYMBOL(bif_ctrl_get);

/**
 * bif_ctrl_put() - frees a BIF controller handle
 * @ctrl:	BIF controller consumer handle
 */
void bif_ctrl_put(struct bif_ctrl *ctrl)
{
	if (!IS_ERR_OR_NULL(ctrl) && ctrl->exclusive_lock)
		mutex_unlock(&ctrl->bdev->mutex);
	kfree(ctrl);
}
EXPORT_SYMBOL(bif_ctrl_put);

static bool bif_slave_object_match(const struct bif_object *object,
		const struct bif_match_criteria *criteria)
{
	return (object->type == criteria->obj_type)
		&& (object->version == criteria->obj_version
			|| !(criteria->match_mask & BIF_MATCH_OBJ_VERSION))
		&& (object->manufacturer_id == criteria->obj_manufacturer_id
		    || !(criteria->match_mask & BIF_MATCH_OBJ_MANUFACTURER_ID));
}

/*
 * Returns true if all parameters are matched, otherwise false.
 * function_type and function_version mean that their exists some function in
 * the slave which has the specified type and subtype.  ctrl == NULL is treated
 * as a wildcard.
 */
static bool bif_slave_match(struct bif_ctrl *ctrl,
	struct bif_slave_dev *sdev, const struct bif_match_criteria *criteria)
{
	int i, type, version;
	struct bif_object *object;
	bool function_found = false;
	bool object_found = false;

	if (ctrl && (ctrl->bdev != sdev->bdev))
		return false;

	if (!sdev->present
	    && (!(criteria->match_mask & BIF_MATCH_IGNORE_PRESENCE)
		|| ((criteria->match_mask & BIF_MATCH_IGNORE_PRESENCE)
		    && !criteria->ignore_presence)))
		return false;

	if ((criteria->match_mask & BIF_MATCH_MANUFACTURER_ID)
	    && sdev->l1_data.manufacturer_id != criteria->manufacturer_id)
		return false;

	if ((criteria->match_mask & BIF_MATCH_PRODUCT_ID)
	    && sdev->l1_data.product_id != criteria->product_id)
		return false;

	if (criteria->match_mask & BIF_MATCH_FUNCTION_TYPE) {
		if (!sdev->function_directory)
			return false;
		for (i = 0; i < sdev->l1_data.length / 4; i++) {
			type = sdev->function_directory[i].function_type;
			version = sdev->function_directory[i].function_version;
			if (type == criteria->function_type &&
				(version == criteria->function_version
					|| !(criteria->match_mask
					       & BIF_MATCH_FUNCTION_VERSION))) {
				function_found = true;
				break;
			}
		}
		if (!function_found)
			return false;
	}

	if (criteria->match_mask & BIF_MATCH_OBJ_TYPE) {
		if (!sdev->nvm_function)
			return false;
		bif_ctrl_lock(ctrl);
		list_for_each_entry(object, &sdev->nvm_function->object_list,
					list) {
			if (bif_slave_object_match(object, criteria)) {
				object_found = true;
				break;
			}
		}
		bif_ctrl_unlock(ctrl);
		if (!object_found)
			return false;
	}

	return true;
}

/**
 * bif_slave_match_count() - returns the number of slaves associated with the
 *			specified BIF controller which fit the matching
 *			criteria
 * @ctrl:		BIF controller consumer handle
 * @match_criteria:	Matching criteria used to filter slaves
 */
int bif_slave_match_count(struct bif_ctrl *ctrl,
			const struct bif_match_criteria *match_criteria)
{
	struct bif_slave_dev *sdev;
	int count = 0;

	mutex_lock(&bif_sdev_list_mutex);

	list_for_each_entry(sdev, &bif_sdev_list, list) {
		if (bif_slave_match(ctrl, sdev, match_criteria))
			count++;
	}

	mutex_unlock(&bif_sdev_list_mutex);

	return count;
}
EXPORT_SYMBOL(bif_slave_match_count);

/**
 * bif_slave_match_get() - get a slave handle for the id'th slave associated
 *			with the specified BIF controller which fits the
 *			matching criteria
 * @ctrl:		BIF controller consumer handle
 * @id:			Index into the set of matching slaves
 * @match_criteria:	Matching criteria used to filter slaves
 *
 * id must be in the range [0, bif_slave_match_count(ctrl, match_criteria) - 1].
 *
 * Returns a BIF slave handle if successful or an ERR_PTR if not.
 */
struct bif_slave *bif_slave_match_get(struct bif_ctrl *ctrl,
	unsigned int id, const struct bif_match_criteria *match_criteria)
{
	struct bif_slave_dev *sdev;
	struct bif_slave *slave = ERR_PTR(-ENODEV);
	struct bif_slave_dev *sdev_found = NULL;
	int count = 0;

	mutex_lock(&bif_sdev_list_mutex);

	list_for_each_entry(sdev, &bif_sdev_list, list) {
		if (bif_slave_match(ctrl, sdev, match_criteria))
			count++;
		if (count == id + 1) {
			sdev_found = sdev;
			break;
		}
	}

	mutex_unlock(&bif_sdev_list_mutex);

	if (sdev_found) {
		slave = kzalloc(sizeof(*slave), GFP_KERNEL);
		if (!slave) {
			pr_err("Slave allocation failed\n");
			slave = ERR_PTR(-ENOMEM);
		} else {
			slave->sdev = sdev_found;
			slave->ctrl.bdev = sdev_found->bdev;
		}
	}

	return slave;
}
EXPORT_SYMBOL(bif_slave_match_get);

/**
 * bif_slave_put() - frees a BIF slave handle
 * @slave:	BIF slave handle
 */
void bif_slave_put(struct bif_slave *slave)
{
	if (!IS_ERR_OR_NULL(slave) && slave->ctrl.exclusive_lock)
		mutex_unlock(&slave->sdev->bdev->mutex);
	kfree(slave);
}
EXPORT_SYMBOL(bif_slave_put);

/**
 * bif_slave_find_function() - get the function pointer and version of a
 *			BIF function if it is present on the specified slave
 * @slave:		BIF slave handle
 * @function:		BIF function to search for inside of the slave
 * @version:		If the function is found, then 'version' is set to the
 *			version value of the function
 * @function_pointer:	If the function is found, then 'function_pointer' is set
 *			to the BIF slave address of the function
 *
 * Returns 0 for success or errno if an error occurred.  If the function is not
 * found in the slave, then -ENODEV is returned.
 */
int bif_slave_find_function(struct bif_slave *slave, u8 function, u8 *version,
				u16 *function_pointer)
{
	int rc = -ENODEV;
	struct bif_ddb_l2_data *func;
	int i;

	if (IS_ERR_OR_NULL(slave) || IS_ERR_OR_NULL(version)
	    || IS_ERR_OR_NULL(function_pointer)) {
		pr_err("Invalid pointer input.\n");
		return -EINVAL;
	}

	func = slave->sdev->function_directory;

	for (i = 0; i < slave->sdev->l1_data.length / 4; i++) {
		if (function == func[i].function_type) {
			*version = func[i].function_version;
			*function_pointer = func[i].function_pointer;
			rc = 0;
			break;
		}
	}

	return rc;
}
EXPORT_SYMBOL(bif_slave_find_function);

static bool bif_object_match(const struct bif_object *object,
		const struct bif_obj_match_criteria *criteria)
{
	return (object->type == criteria->type
			|| !(criteria->match_mask & BIF_OBJ_MATCH_TYPE))
		&& (object->version == criteria->version
			|| !(criteria->match_mask & BIF_OBJ_MATCH_VERSION))
		&& (object->manufacturer_id == criteria->manufacturer_id
		    || !(criteria->match_mask & BIF_OBJ_MATCH_MANUFACTURER_ID));
}

/**
 * bif_object_match_count() - returns the number of objects associated with the
 *			specified BIF slave which fit the matching criteria
 * @slave:		BIF slave handle
 * @match_criteria:	Matching criteria used to filter objects
 */
int bif_object_match_count(struct bif_slave *slave,
			const struct bif_obj_match_criteria *match_criteria)
{
	struct bif_object *object;
	int count = 0;

	if (IS_ERR_OR_NULL(slave) || IS_ERR_OR_NULL(match_criteria)) {
		pr_err("Invalid pointer input.\n");
		return -EINVAL;
	}

	if (!slave->sdev->nvm_function)
		return 0;

	bif_slave_ctrl_lock(slave);
	list_for_each_entry(object, &slave->sdev->nvm_function->object_list,
			    list) {
		if (bif_object_match(object, match_criteria))
			count++;
	}
	bif_slave_ctrl_unlock(slave);

	return count;
}
EXPORT_SYMBOL(bif_object_match_count);

/**
 * bif_object_match_get() - get a BIF object handle for the id'th object found
 *			in the non-volatile memory of the specified BIF slave
 *			which fits the matching criteria
 * @slave:		BIF slave handle
 * @id:			Index into the set of matching objects
 * @match_criteria:	Matching criteria used to filter objects
 *
 * id must be in range [0, bif_object_match_count(slave, match_criteria) - 1].
 *
 * Returns a BIF object handle if successful or an ERR_PTR if not.  This handle
 * must be freed using bif_object_put() when it is no longer needed.
 */
struct bif_object *bif_object_match_get(struct bif_slave *slave,
	unsigned int id, const struct bif_obj_match_criteria *match_criteria)
{
	struct bif_object *object;
	struct bif_object *object_found = NULL;
	struct bif_object *object_consumer = ERR_PTR(-ENODEV);
	int count = 0;

	if (IS_ERR_OR_NULL(slave) || IS_ERR_OR_NULL(match_criteria)) {
		pr_err("Invalid pointer input.\n");
		return ERR_PTR(-EINVAL);
	}

	if (!slave->sdev->nvm_function)
		return object_consumer;

	bif_slave_ctrl_lock(slave);
	list_for_each_entry(object, &slave->sdev->nvm_function->object_list,
			    list) {
		if (bif_object_match(object, match_criteria))
			count++;
		if (count == id + 1) {
			object_found = object;
			break;
		}
	}

	if (object_found) {
		object_consumer = kmemdup(object_found,
					sizeof(*object_consumer), GFP_KERNEL);
		if (!object_consumer) {
			pr_err("out of memory\n");
			object_consumer = ERR_PTR(-ENOMEM);
			goto done;
		}

		object_consumer->data = kmemdup(object_found->data,
					  object_found->length - 8, GFP_KERNEL);
		if (!object_consumer->data) {
			pr_err("out of memory\n");
			kfree(object_consumer);
			object_consumer = ERR_PTR(-ENOMEM);
			goto done;
		}

		/*
		 * Use prev pointer in consumer struct to point to original
		 * struct in the internal linked list.
		 */
		object_consumer->list.prev = &object_found->list;
	}

done:
	bif_slave_ctrl_unlock(slave);

	return object_consumer;

}
EXPORT_SYMBOL(bif_object_match_get);

/**
 * bif_object_put() - frees the memory allocated for a BIF object pointer
 *			returned by bif_object_match_get()
 * @object:		BIF object to free
 */
void bif_object_put(struct bif_object *object)
{
	if (object)
		kfree(object->data);
	kfree(object);
}
EXPORT_SYMBOL(bif_object_put);

/* Copies the contents of object into buf following MIPI-BIF formatting. */
static void bif_object_flatten(u8 *buf, const struct bif_object *object)
{
	buf[0]			= object->type;
	buf[1]			= object->version;
	buf[2]			= object->manufacturer_id >> 8;
	buf[3]			= object->manufacturer_id;
	buf[4]			= object->length >> 8;
	buf[5]			= object->length;
	memcpy(&buf[6], object->data, object->length - 8);
	buf[object->length - 2]	= object->crc >> 8;
	buf[object->length - 1]	= object->crc;
}

/**
 * bif_object_write() - writes a new BIF object at the end of the object list in
 *			the non-volatile memory of a slave
 * @slave:		BIF slave handle
 * @type:		Type of the object
 * @version:		Version of the object
 * @manufacturer_id:	Manufacturer ID number allocated by MIPI
 * @data:		Data contained in the object
 * @data_len:		Length of the data
 *
 * Returns 0 on success or errno on failure.  This function will fail if the NVM
 * lock points to an offset after the BIF object list terminator (0x00).
 */
int bif_object_write(struct bif_slave *slave, u8 type, u8 version,
			u16 manufacturer_id, const u8 *data, int data_len)
{
	struct bif_object *object;
	struct bif_object *tail_object;
	struct bif_nvm_function	*nvm;
	int rc;
	int add_null = 0;
	u16 offset = 0;
	u8 *buf;

	if (IS_ERR_OR_NULL(slave) || IS_ERR_OR_NULL(data)) {
		pr_err("Invalid input pointer\n");
		return -EINVAL;
	}

	nvm = slave->sdev->nvm_function;
	if (!nvm) {
		pr_err("BIF slave has no NVM function\n");
		return -ENODEV;
	}

	bif_slave_ctrl_lock(slave);
	if (nvm->object_count > 0) {
		tail_object = list_entry(nvm->object_list.prev,
					struct bif_object, list);
		offset = tail_object->addr - nvm->nvm_base_address
				+ tail_object->length;
	}

	if (offset < nvm->nvm_lock_offset) {
		pr_err("Cannot write BIF object to NVM because the end of the object list is locked (end=%d < lock=%d)\n",
			offset, nvm->nvm_lock_offset);
		rc = -EPERM;
		goto error_unlock;
	} else if (offset + data_len + 8 > nvm->nvm_size) {
		pr_err("Cannot write BIF object to NVM because there is not enough remaining space (size=%d > remaining=%d)\n",
			data_len + 8, nvm->nvm_size - offset);
		rc = -EINVAL;
		goto error_unlock;
	}

	if (offset + data_len + 8 < nvm->nvm_size)
		add_null = 1;
	object = kzalloc(sizeof(*object), GFP_KERNEL);
	if (!object) {
		pr_err("kzalloc failed\n");
		rc = -ENOMEM;
		goto error_unlock;
	}

	object->data = kzalloc(data_len, GFP_KERNEL);
	if (!object->data) {
		pr_err("kzalloc failed\n");
		rc = -ENOMEM;
		goto free_object;
	}

	buf = kzalloc(data_len + 8 + add_null, GFP_KERNEL);
	if (!buf) {
		pr_err("kzalloc failed\n");
		rc = -ENOMEM;
		goto free_data;
	}

	object->type		= type;
	object->version		= version;
	object->manufacturer_id	= manufacturer_id;
	object->length		= data_len + 8;
	memcpy(object->data, data, data_len);
	object->crc		= bif_object_crc_ccitt(object);
	object->addr		= offset + nvm->nvm_base_address;

	bif_object_flatten(buf, object);
	if (add_null)
		buf[object->length] = BIF_OBJ_END_OF_LIST;

	rc = _bif_slave_nvm_raw_write(slave->sdev, offset, buf,
					object->length + add_null);
	if (rc < 0) {
		pr_err("NVM write failed, rc=%d\n", rc);
		kfree(buf);
		goto free_data;
	}
	kfree(buf);

	list_add_tail(&object->list, &nvm->object_list);
	nvm->object_count++;

	bif_slave_ctrl_unlock(slave);

	return rc;

free_data:
	kfree(object->data);
free_object:
	kfree(object);
error_unlock:
	bif_slave_ctrl_unlock(slave);

	return rc;

}
EXPORT_SYMBOL(bif_object_write);

/*
 * Returns a pointer to the internal object referenced by a consumer object
 * if it exists.  Returns NULL if the internal object cannot be found.
 */
static struct bif_object *bif_object_consumer_search(
	struct bif_nvm_function *nvm, const struct bif_object *consumer_object)
{
	struct bif_object *object = NULL;
	struct bif_object *search_object;

	/*
	 * Internal struct in object linked list is pointed to by consumer
	 * object list.prev.
	 */
	search_object = list_entry(consumer_object->list.prev,
					struct bif_object, list);

	list_for_each_entry(object, &nvm->object_list, list) {
		if (object == search_object)
			break;
	}

	if (object != search_object)
		return NULL;

	return object;
}

/**
 * bif_object_overwrite() - overwrites an existing BIF object found in the
 *			non-volatile memory of a slave
 * @slave:		BIF slave handle
 * @object:		Existing object in the slave to overwrite
 * @type:		Type of the object
 * @version:		Version of the object
 * @manufacturer_id:	Manufacturer ID number allocated by MIPI
 * @data:		Data contained in the object
 * @data_len:		Length of the data
 *
 * Returns 0 on success or errno on failure.  The data stored within 'object'
 * is updated to the new values upon success.  The new data written to the
 * object must have exactly the same length as the old data (i.e.
 * data_len == object->length - 8).
 *
 * This function will fail if the NVM lock points to an offset after the
 * beginning of the existing BIF object.
 */
int bif_object_overwrite(struct bif_slave *slave,
	struct bif_object *object, u8 type, u8 version,
	u16 manufacturer_id, const u8 *data, int data_len)
{
	struct bif_object *edit_object = NULL;
	struct bif_nvm_function *nvm;
	int rc;
	u16 crc;
	u8 *buf;

	if (IS_ERR_OR_NULL(slave) || IS_ERR_OR_NULL(object)
	    || IS_ERR_OR_NULL(data)) {
		pr_err("Invalid input pointer\n");
		return -EINVAL;
	}

	nvm = slave->sdev->nvm_function;
	if (!nvm) {
		pr_err("BIF slave has no NVM function\n");
		return -ENODEV;
	}

	if (data_len + 8 != object->length) {
		pr_err("New data length=%d is different from existing length=%d\n",
			data_len, object->length - 8);
		return -EINVAL;
	}

	bif_slave_ctrl_lock(slave);

	edit_object = bif_object_consumer_search(nvm, object);
	if (!edit_object) {
		pr_err("BIF object not found within slave\n");
		rc = -EINVAL;
		goto error_unlock;
	}

	if (edit_object->addr - nvm->nvm_base_address < nvm->nvm_lock_offset) {
		pr_err("Cannot overwrite BIF object in NVM because some portion of it is locked\n");
		rc = -EPERM;
		goto error_unlock;
	}

	buf = kzalloc(data_len + 8, GFP_KERNEL);
	if (!buf) {
		pr_err("kzalloc failed\n");
		rc = -ENOMEM;
		goto error_unlock;
	}

	buf[0]			= type;
	buf[1]			= version;
	buf[2]			= manufacturer_id >> 8;
	buf[3]			= manufacturer_id;
	buf[4]			= (data_len + 8) >> 8;
	buf[5]			= data_len + 8;
	memcpy(&buf[6], data, data_len);
	crc			= bif_crc_ccitt(buf, data_len + 6);
	buf[data_len + 6]	= crc >> 8;
	buf[data_len + 7]	= crc;

	rc = _bif_slave_nvm_raw_write(slave->sdev,
		object->addr - nvm->nvm_base_address, buf, data_len + 8);
	if (rc < 0) {
		pr_err("NVM write failed, rc=%d\n", rc);
		kfree(buf);
		goto error_unlock;
	}
	kfree(buf);

	/* Update internal object struct. */
	edit_object->type		= type;
	edit_object->version		= version;
	edit_object->manufacturer_id	= manufacturer_id;
	edit_object->length		= data_len + 8;
	memcpy(edit_object->data, data, data_len);
	edit_object->crc		= crc;

	/* Update consumer object struct. */
	object->type			= type;
	object->version			= version;
	object->manufacturer_id		= manufacturer_id;
	object->length			= data_len + 8;
	memcpy(object->data, data, data_len);
	object->crc			= crc;

error_unlock:
	bif_slave_ctrl_unlock(slave);

	return rc;
}
EXPORT_SYMBOL(bif_object_overwrite);

/**
 * bif_object_delete() - deletes an existing BIF object found in the
 *			non-volatile memory of a slave.  Objects found in the
 *			object list in the NVM of the slave are shifted forward
 *			in order to fill the hole left by the deleted object
 * @slave:		BIF slave handle
 * @object:		Existing object in the slave to delete
 *
 * Returns 0 on success or errno on failure.  bif_object_put() must still be
 * called after this function in order to free the memory in the consumer
 * 'object' struct pointer.
 *
 * This function will fail if the NVM lock points to an offset after the
 * beginning of the existing BIF object.
 */
int bif_object_delete(struct bif_slave *slave, const struct bif_object *object)
{
	struct bif_object *del_object = NULL;
	struct bif_object *tail_object;
	struct bif_nvm_function *nvm;
	bool found = false;
	int pos = 0;
	int rc;
	u8 *buf;

	if (IS_ERR_OR_NULL(slave) || IS_ERR_OR_NULL(object)) {
		pr_err("Invalid input pointer\n");
		return -EINVAL;
	}

	nvm = slave->sdev->nvm_function;
	if (!nvm) {
		pr_err("BIF slave has no NVM function\n");
		return -ENODEV;
	}

	bif_slave_ctrl_lock(slave);

	del_object = bif_object_consumer_search(nvm, object);
	if (!del_object) {
		pr_err("BIF object not found within slave\n");
		rc = -EINVAL;
		goto error_unlock;
	}

	if (del_object->addr - nvm->nvm_base_address < nvm->nvm_lock_offset) {
		pr_err("Cannot delete BIF object in NVM because some portion of it is locked\n");
		rc = -EPERM;
		goto error_unlock;
	}

	buf = kmalloc(nvm->nvm_size, GFP_KERNEL);
	if (!buf) {
		pr_err("kzalloc failed\n");
		rc = -ENOMEM;
		goto error_unlock;
	}

	/*
	 * Copy the contents of objects after the one to be deleted into a flat
	 * array.
	 */
	list_for_each_entry(tail_object, &nvm->object_list, list) {
		if (found) {
			bif_object_flatten(&buf[pos], tail_object);
			pos += tail_object->length;
		} else if (tail_object == del_object) {
			found = true;
		}
	}

	/* Add the list terminator. */
	buf[pos++] = BIF_OBJ_END_OF_LIST;

	rc = _bif_slave_nvm_raw_write(slave->sdev,
		del_object->addr - nvm->nvm_base_address, buf, pos);
	if (rc < 0) {
		pr_err("NVM write failed, rc=%d\n", rc);
		kfree(buf);
		goto error_unlock;
	}
	kfree(buf);

	/* Update the addresses of the objects after the one to be deleted. */
	found = false;
	list_for_each_entry(tail_object, &nvm->object_list, list) {
		if (found)
			tail_object->addr -= del_object->length;
		else if (tail_object == del_object)
			found = true;
	}

	list_del(&del_object->list);
	kfree(del_object->data);
	kfree(del_object);
	nvm->object_count--;

error_unlock:
	bif_slave_ctrl_unlock(slave);

	return rc;
}
EXPORT_SYMBOL(bif_object_delete);

/**
 * bif_slave_read() - read contiguous memory values from a BIF slave
 * @slave:	BIF slave handle
 * @addr:	BIF slave address to begin reading at
 * @buf:	Buffer to fill with memory values
 * @len:	Number of byte to read
 *
 * Returns 0 for success or errno if an error occurred.
 */
int bif_slave_read(struct bif_slave *slave, u16 addr, u8 *buf, int len)
{
	int rc;

	if (IS_ERR_OR_NULL(slave) || IS_ERR_OR_NULL(buf)) {
		pr_err("Invalid pointer input.\n");
		return -EINVAL;
	}

	bif_slave_ctrl_lock(slave);

	rc = _bif_slave_read(slave->sdev, addr, buf, len);
	if (rc)
		pr_err("BIF slave read failed, rc=%d\n", rc);

	bif_slave_ctrl_unlock(slave);

	return rc;
}
EXPORT_SYMBOL(bif_slave_read);

/**
 * bif_slave_write() - write contiguous memory values to a BIF slave
 * @slave:	BIF slave handle
 * @addr:	BIF slave address to begin writing at
 * @buf:	Buffer containing values to write
 * @len:	Number of byte to write
 *
 * Returns 0 for success or errno if an error occurred.
 */
int bif_slave_write(struct bif_slave *slave, u16 addr, u8 *buf, int len)
{
	int rc;

	if (IS_ERR_OR_NULL(slave) || IS_ERR_OR_NULL(buf)) {
		pr_err("Invalid pointer input.\n");
		return -EINVAL;
	}

	bif_slave_ctrl_lock(slave);

	rc = _bif_slave_write(slave->sdev, addr, buf, len);
	if (rc)
		pr_err("BIF slave write failed, rc=%d\n", rc);

	bif_slave_ctrl_unlock(slave);

	return rc;
}
EXPORT_SYMBOL(bif_slave_write);

/**
 * bif_slave_nvm_raw_read() - read contiguous memory values from a BIF slave's
 *		non-volatile memory (NVM)
 * @slave:	BIF slave handle
 * @offset:	Offset from the beginning of BIF slave NVM to begin reading at
 * @buf:	Buffer to fill with memory values
 * @len:	Number of byte to read
 *
 * Returns 0 for success or errno if an error occurred.
 */
int bif_slave_nvm_raw_read(struct bif_slave *slave, u16 offset, u8 *buf,
				int len)
{
	if (IS_ERR_OR_NULL(slave)) {
		pr_err("Invalid slave pointer=%ld\n", PTR_ERR(slave));
		return -EINVAL;
	} else if (IS_ERR_OR_NULL(buf)) {
		pr_err("Invalid buffer pointer=%ld\n", PTR_ERR(buf));
		return -EINVAL;
	} else if (!slave->sdev->nvm_function) {
		pr_err("BIF slave has no NVM function\n");
		return -ENODEV;
	} else if (offset + len > slave->sdev->nvm_function->nvm_size) {
		pr_err("read offset + len = %d > NVM size = %d\n",
			offset + len, slave->sdev->nvm_function->nvm_size);
		return -EINVAL;
	}

	return bif_slave_read(slave,
		slave->sdev->nvm_function->nvm_base_address + offset, buf, len);
}
EXPORT_SYMBOL(bif_slave_nvm_raw_read);

/**
 * bif_slave_nvm_raw_write() - write contiguous memory values to a BIF slave's
 *		non-volatile memory (NVM)
 * @slave:	BIF slave handle
 * @offset:	Offset from the beginning of BIF slave NVM to begin writing at
 * @buf:	Buffer containing values to write
 * @len:	Number of byte to write
 *
 * Note that this function does *not* respect the MIPI-BIF object data
 * formatting specification.  It can cause corruption of the object data list
 * stored in NVM if used improperly.
 *
 * Returns 0 for success or errno if an error occurred.
 */
int bif_slave_nvm_raw_write(struct bif_slave *slave, u16 offset, u8 *buf,
				int len)
{
	int rc;

	if (IS_ERR_OR_NULL(slave)) {
		pr_err("Invalid slave pointer=%ld\n", PTR_ERR(slave));
		return -EINVAL;
	} else if (IS_ERR_OR_NULL(buf)) {
		pr_err("Invalid buffer pointer=%ld\n", PTR_ERR(buf));
		return -EINVAL;
	}

	bif_slave_ctrl_lock(slave);
	rc = _bif_slave_nvm_raw_write(slave->sdev, offset, buf, len);
	bif_slave_ctrl_unlock(slave);

	return rc;
}
EXPORT_SYMBOL(bif_slave_nvm_raw_write);

/**
 * bif_slave_is_present() - check if a slave is currently physically present
 *		in the system
 * @slave:	BIF slave handle
 *
 * Returns 1 if the slave is present, 0 if the slave is not present, or errno
 * if an error occurred.
 *
 * This function can be used by BIF consumer drivers to check if their slave
 * handles are still meaningful after battery reinsertion.
 */
int bif_slave_is_present(struct bif_slave *slave)
{
	if (IS_ERR_OR_NULL(slave)) {
		pr_err("Invalid pointer input.\n");
		return -EINVAL;
	}

	return slave->sdev->present;
}
EXPORT_SYMBOL(bif_slave_is_present);

/**
 * bif_slave_is_selected() - check if a slave is currently selected on the BIF
 *		bus
 * @slave:	BIF slave handle
 *
 * Returns 1 if the slave is selected, 0 if the slave is not selected, or errno
 * if an error occurred.
 *
 * This function should not be required under normal circumstances since the
 * bif-core framework ensures that slaves are always selected when needed.
 * It would be most useful when used as a helper in conjunction with
 * bif_ctrl_bus_lock() and the raw transaction functions.
 */
int bif_slave_is_selected(struct bif_slave *slave)
{
	int rc;

	if (IS_ERR_OR_NULL(slave)) {
		pr_err("Invalid pointer input.\n");
		return -EINVAL;
	}

	if (slave->sdev->bdev->selected_sdev != slave->sdev)
		return false;

	bif_slave_ctrl_lock(slave);
	rc = bif_is_slave_selected(slave->sdev->bdev);
	bif_slave_ctrl_unlock(slave);

	return rc;
}
EXPORT_SYMBOL(bif_slave_is_selected);

/**
 * bif_slave_select() - select a slave on the BIF bus
 * @slave:	BIF slave handle
 *
 * Returns 0 on success or errno if an error occurred.
 *
 * This function should not be required under normal circumstances since the
 * bif-core framework ensures that slaves are always selected when needed.
 * It would be most useful when used as a helper in conjunction with
 * bif_ctrl_bus_lock() and the raw transaction functions.
 */
int bif_slave_select(struct bif_slave *slave)
{
	int rc;

	if (IS_ERR_OR_NULL(slave)) {
		pr_err("Invalid pointer input.\n");
		return -EINVAL;
	}

	bif_slave_ctrl_lock(slave);
	slave->sdev->bdev->selected_sdev = NULL;
	rc = bif_select_slave(slave->sdev);
	bif_slave_ctrl_unlock(slave);

	return rc;
}
EXPORT_SYMBOL(bif_slave_select);

/**
 * bif_ctrl_raw_transaction() - perform a raw BIF transaction on the bus which
 *			expects no slave response
 * @ctrl:		BIF controller consumer handle
 * @transaction:	BIF transaction to carry out.  This should be one of the
 *			values in enum bif_transaction.
 * @data:		8-bit data to use in the transaction.  The meaning of
 *			this data depends upon the transaction that is to be
 *			performed.
 *
 * When performing a bus command (BC) transaction, values in enum
 * bif_bus_command may be used for the data parameter.  Additional manufacturer
 * specific values may also be used in a BC transaction.
 *
 * Returns 0 on success or errno if an error occurred.
 *
 * This function should only need to be used when BIF transactions are required
 * that are not handled by the bif-core directly.
 */
int bif_ctrl_raw_transaction(struct bif_ctrl *ctrl, int transaction, u8 data)
{
	int rc;

	if (IS_ERR_OR_NULL(ctrl)) {
		pr_err("Invalid pointer input.\n");
		return -EINVAL;
	}

	bif_ctrl_lock(ctrl);

	rc = ctrl->bdev->desc->ops->bus_transaction(ctrl->bdev, transaction,
							data);
	if (rc)
		pr_err("BIF bus transaction failed, rc=%d\n", rc);

	bif_ctrl_unlock(ctrl);

	return rc;
}
EXPORT_SYMBOL(bif_ctrl_raw_transaction);

/**
 * bif_ctrl_raw_transaction_read() - perform a raw BIF transaction on the bus
 *			which expects an RD or TACK slave response word
 * @ctrl:		BIF controller consumer handle
 * @transaction:	BIF transaction to carry out.  This should be one of the
 *			values in enum bif_transaction.
 * @data:		8-bit data to use in the transaction.  The meaning of
 *			this data depends upon the transaction that is to be
 *			performed.
 * @response:		Pointer to an integer which is filled with the 11-bit
 *			slave response word upon success.  The 11-bit format is
 *			(MSB to LSB) BCF, ACK, EOT, D7-D0.
 *
 * When performing a bus command (BC) transaction, values in enum
 * bif_bus_command may be used for the data parameter.  Additional manufacturer
 * specific values may also be used in a BC transaction.
 *
 * Returns 0 on success or errno if an error occurred.
 *
 * This function should only need to be used when BIF transactions are required
 * that are not handled by the bif-core directly.
 */
int bif_ctrl_raw_transaction_read(struct bif_ctrl *ctrl, int transaction,
					u8 data, int *response)
{
	int rc;

	if (IS_ERR_OR_NULL(ctrl) || IS_ERR_OR_NULL(response)) {
		pr_err("Invalid pointer input.\n");
		return -EINVAL;
	}

	bif_ctrl_lock(ctrl);

	rc = ctrl->bdev->desc->ops->bus_transaction_read(ctrl->bdev,
					transaction, data, response);
	if (rc)
		pr_err("BIF bus transaction failed, rc=%d\n", rc);

	bif_ctrl_unlock(ctrl);

	return rc;
}
EXPORT_SYMBOL(bif_ctrl_raw_transaction_read);

/**
 * bif_ctrl_raw_transaction_query() - perform a raw BIF transaction on the bus
 *			which expects a BQ slave response
 * @ctrl:		BIF controller consumer handle
 * @transaction:	BIF transaction to carry out.  This should be one of the
 *			values in enum bif_transaction.
 * @data:		8-bit data to use in the transaction.  The meaning of
 *			this data depends upon the transaction that is to be
 *			performed.
 * @query_response:	Pointer to boolean which is set to true if a BQ pulse
 *			is receieved, or false if no BQ pulse is received before
 *			timing out.
 *
 * When performing a bus command (BC) transaction, values in enum
 * bif_bus_command may be used for the data parameter.  Additional manufacturer
 * specific values may also be used in a BC transaction.
 *
 * Returns 0 on success or errno if an error occurred.
 *
 * This function should only need to be used when BIF transactions are required
 * that are not handled by the bif-core directly.
 */
int bif_ctrl_raw_transaction_query(struct bif_ctrl *ctrl, int transaction,
		u8 data, bool *query_response)
{
	int rc;

	if (IS_ERR_OR_NULL(ctrl) || IS_ERR_OR_NULL(query_response)) {
		pr_err("Invalid pointer input.\n");
		return -EINVAL;
	}

	bif_ctrl_lock(ctrl);

	rc = ctrl->bdev->desc->ops->bus_transaction_query(ctrl->bdev,
					transaction, data, query_response);
	if (rc)
		pr_err("BIF bus transaction failed, rc=%d\n", rc);

	bif_ctrl_unlock(ctrl);

	return rc;
}
EXPORT_SYMBOL(bif_ctrl_raw_transaction_query);

/**
 * bif_ctrl_bus_lock() - lock the BIF bus of a controller for exclusive access
 * @ctrl:	BIF controller consumer handle
 *
 * This function should only need to be called in circumstances where a BIF
 * consumer is issuing special BIF bus commands that have strict ordering
 * requirements.
 */
void bif_ctrl_bus_lock(struct bif_ctrl *ctrl)
{
	if (IS_ERR_OR_NULL(ctrl)) {
		pr_err("Invalid controller handle.\n");
		return;
	}

	if (ctrl->exclusive_lock) {
		pr_err("BIF bus exclusive lock already held\n");
		return;
	}

	mutex_lock(&ctrl->bdev->mutex);
	ctrl->exclusive_lock = true;
	bif_cancel_irq_mode_work(ctrl->bdev);
}
EXPORT_SYMBOL(bif_ctrl_bus_lock);

/**
 * bif_ctrl_bus_unlock() - lock the BIF bus of a controller that was previously
 *		locked for exclusive access
 * @ctrl:	BIF controller consumer handle
 *
 * This function must only be called after first calling bif_ctrl_bus_lock().
 */
void bif_ctrl_bus_unlock(struct bif_ctrl *ctrl)
{
	if (IS_ERR_OR_NULL(ctrl)) {
		pr_err("Invalid controller handle.\n");
		return;
	}

	if (!ctrl->exclusive_lock) {
		pr_err("BIF bus exclusive lock not already held\n");
		return;
	}

	ctrl->exclusive_lock = false;
	bif_schedule_irq_mode_work(ctrl->bdev);
	mutex_unlock(&ctrl->bdev->mutex);
}
EXPORT_SYMBOL(bif_ctrl_bus_unlock);

/**
 * bif_ctrl_measure_rid() - measure the battery pack Rid pull-down resistance
 *		in ohms
 * @ctrl:	BIF controller consumer handle
 *
 * Returns the resistance of the Rid resistor in ohms if successful or errno
 * if an error occurred.
 */
int bif_ctrl_measure_rid(struct bif_ctrl *ctrl)
{
	int rc;

	if (IS_ERR_OR_NULL(ctrl)) {
		pr_err("Invalid controller handle.\n");
		return -ENODEV;
	}

	if (!ctrl->bdev->desc->ops->get_battery_rid) {
		pr_err("Cannot measure Rid.\n");
		return -ENXIO;
	}

	bif_ctrl_lock(ctrl);

	rc = ctrl->bdev->desc->ops->get_battery_rid(ctrl->bdev);
	if (rc < 0)
		pr_err("Error during Rid measurement, rc=%d\n", rc);

	bif_ctrl_unlock(ctrl);

	return rc;
}
EXPORT_SYMBOL(bif_ctrl_measure_rid);

/**
 * bif_ctrl_get_bus_period() - get the BIF bus period (tau_bif) in nanoseconds
 * @ctrl:	BIF controller consumer handle
 *
 * Returns the currently configured bus period in nanoseconds if successful or
 * errno if an error occurred.
 */
int bif_ctrl_get_bus_period(struct bif_ctrl *ctrl)
{
	int rc;

	if (IS_ERR_OR_NULL(ctrl)) {
		pr_err("Invalid controller handle.\n");
		return -ENODEV;
	}

	if (!ctrl->bdev->desc->ops->get_bus_period) {
		pr_err("Cannot get the BIF bus period.\n");
		return -ENXIO;
	}

	rc = ctrl->bdev->desc->ops->get_bus_period(ctrl->bdev);
	if (rc < 0)
		pr_err("Error during bus period retrieval, rc=%d\n", rc);

	return rc;
}
EXPORT_SYMBOL(bif_ctrl_get_bus_period);

/**
 * bif_ctrl_set_bus_period() - set the BIF bus period (tau_bif) in nanoseconds
 * @ctrl:	BIF controller consumer handle
 * @period_ns:	BIF bus period in nanoseconds to use
 *
 * If the exact period is not supported by the BIF controller hardware, then the
 * next larger supported period will be used.
 *
 * Returns 0 on success or errno if an error occurred.
 */
int bif_ctrl_set_bus_period(struct bif_ctrl *ctrl, int period_ns)
{
	int rc;

	if (IS_ERR_OR_NULL(ctrl)) {
		pr_err("Invalid controller handle.\n");
		return -ENODEV;
	}

	if (!ctrl->bdev->desc->ops->set_bus_period) {
		pr_err("Cannot set the BIF bus period.\n");
		return -ENXIO;
	}

	bif_ctrl_lock(ctrl);
	rc = ctrl->bdev->desc->ops->set_bus_period(ctrl->bdev, period_ns);
	if (rc)
		pr_err("Error during bus period configuration, rc=%d\n", rc);
	bif_ctrl_unlock(ctrl);

	return rc;
}
EXPORT_SYMBOL(bif_ctrl_set_bus_period);

/**
 * bif_ctrl_get_bus_state() - get the current state of the BIF bus
 * @ctrl:	BIF controller consumer handle
 *
 * Returns a bus state from enum bif_bus_state if successful or errno if an
 * error occurred.
 */
int bif_ctrl_get_bus_state(struct bif_ctrl *ctrl)
{
	int rc;

	if (IS_ERR_OR_NULL(ctrl)) {
		pr_err("Invalid controller handle.\n");
		return -ENODEV;
	}

	rc = ctrl->bdev->desc->ops->get_bus_state(ctrl->bdev);
	if (rc < 0)
		pr_err("Error during bus state retrieval, rc=%d\n", rc);

	return rc;
}
EXPORT_SYMBOL(bif_ctrl_get_bus_state);

/**
 * bif_ctrl_set_bus_state() - set the state of the BIF bus
 * @ctrl:	BIF controller consumer handle
 * @state:	State for the BIF bus to enter
 *
 * Returns 0 on success or errno if an error occurred.
 */
int bif_ctrl_set_bus_state(struct bif_ctrl *ctrl, enum bif_bus_state state)
{
	int rc;

	if (IS_ERR_OR_NULL(ctrl)) {
		pr_err("Invalid controller handle.\n");
		return -ENODEV;
	}

	bif_ctrl_lock(ctrl);

	rc = ctrl->bdev->desc->ops->set_bus_state(ctrl->bdev, state);
	if (rc < 0)
		pr_err("Error during bus state configuration, rc=%d\n", rc);

	/*
	 * Uncache the selected slave if the new bus state results in the slave
	 * becoming unselected.
	 */
	if (state == BIF_BUS_STATE_MASTER_DISABLED
	    || state == BIF_BUS_STATE_POWER_DOWN
	    || state == BIF_BUS_STATE_STANDBY)
		ctrl->bdev->selected_sdev = NULL;

	bif_ctrl_unlock(ctrl);

	return rc;
}
EXPORT_SYMBOL(bif_ctrl_set_bus_state);

/*
 * Check if the specified function is a protocol function and if it is, then
 * instantiate protocol function data for the slave.
 */
static int bif_initialize_protocol_function(struct bif_slave_dev *sdev,
		struct bif_ddb_l2_data *func)
{
	int rc = 0;
	u8 buf[4];

	/* Ensure that this is a protocol function. */
	if (func->function_type != BIF_FUNC_PROTOCOL)
		return 0;

	if (sdev->protocol_function) {
		pr_err("Duplicate protocol function found for BIF slave; DEV_ADR=0x%02X\n",
			sdev->slave_addr);
		return -EPERM;
	}

	sdev->protocol_function = kzalloc(sizeof(struct bif_protocol_function),
						GFP_KERNEL);
	if (!sdev->protocol_function) {
		pr_err("out of memory\n");
		return -ENOMEM;
	}

	rc = _bif_slave_read(sdev, func->function_pointer, buf, 4);
	if (rc) {
		pr_err("Protocol function data read failed, rc=%d\n", rc);
		return rc;
	}

	sdev->protocol_function->protocol_pointer  = buf[0] << 8 | buf[1];
	sdev->protocol_function->device_id_pointer = buf[2] << 8 | buf[3];
	sdev->protocol_function->l2_entry = func;

	rc = _bif_slave_read(sdev, sdev->protocol_function->device_id_pointer,
		sdev->protocol_function->device_id, BIF_DEVICE_ID_BYTE_LENGTH);
	if (rc) {
		pr_err("Device ID read failed, rc=%d\n", rc);
		return rc;
	}

	/* Check if this slave does not have a UID value stored. */
	if (sdev->unique_id_bits_known == 0) {
		sdev->unique_id_bits_known = BIF_UNIQUE_ID_BIT_LENGTH;
		/* Fill in UID using manufacturer ID and device ID. */
		sdev->unique_id[0] = sdev->l1_data.manufacturer_id >> 8;
		sdev->unique_id[1] = sdev->l1_data.manufacturer_id;
		memcpy(&sdev->unique_id[2],
			sdev->protocol_function->device_id,
			BIF_DEVICE_ID_BYTE_LENGTH);
	}

	return rc;
}

/*
 * Check if the specified function is a slave control function and if it is,
 * then instantiate slave control function data for the slave.
 */
static int bif_initialize_slave_control_function(struct bif_slave_dev *sdev,
		struct bif_ddb_l2_data *func)
{
	int rc = 0;
	int i;
	u8 buf[3];

	/* Ensure that this is a slave control function. */
	if (func->function_type != BIF_FUNC_SLAVE_CONTROL)
		return 0;

	if (sdev->slave_ctrl_function) {
		pr_err("Duplicate slave control function found for BIF slave; DEV_ADR=0x%02X\n",
			sdev->slave_addr);
		return -EPERM;
	}

	sdev->slave_ctrl_function
		= kzalloc(sizeof(struct bif_protocol_function), GFP_KERNEL);
	if (!sdev->slave_ctrl_function) {
		pr_err("out of memory\n");
		return -ENOMEM;
	}

	rc = _bif_slave_read(sdev, func->function_pointer, buf, 3);
	if (rc) {
		pr_err("Slave control function data read failed, rc=%d\n", rc);
		return rc;
	}

	sdev->slave_ctrl_function->slave_ctrl_pointer = buf[0] << 8 | buf[1];
	sdev->slave_ctrl_function->task_count
		= buf[2] * SLAVE_CTRL_TASKS_PER_SET;
	sdev->slave_ctrl_function->l2_entry = func;

	if (sdev->slave_ctrl_function->task_count > 0) {
		sdev->slave_ctrl_function->irq_notifier_list =
			kzalloc(sizeof(struct blocking_notifier_head)
			    * sdev->slave_ctrl_function->task_count,
			    GFP_KERNEL);
		if (!sdev->slave_ctrl_function->irq_notifier_list) {
			pr_err("out of memory\n");
			kfree(sdev->slave_ctrl_function);
			return -ENOMEM;
		}

		for (i = 0; i < sdev->slave_ctrl_function->task_count; i++) {
			BLOCKING_INIT_NOTIFIER_HEAD(
			    &sdev->slave_ctrl_function->irq_notifier_list[i]);
		}
	}

	return rc;
}

/*
 * Check if the specified function is an NVM function and if it is, then
 * instantiate NVM function data for the slave and read all objects.
 */
static int bif_initialize_nvm_function(struct bif_slave_dev *sdev,
		struct bif_ddb_l2_data *func)
{
	int rc = 0;
	int data_len, read_size;
	u8 buf[8], object_type;
	struct bif_object *object;
	struct bif_object *temp;
	u16 addr;
	u16 crc;

	/* Ensure that this is an NVM function. */
	if (func->function_type != BIF_FUNC_NVM)
		return 0;

	if (sdev->nvm_function) {
		pr_err("Duplicate NVM function found for BIF slave; DEV_ADR=0x%02X\n",
			sdev->slave_addr);
		return -EPERM;
	}

	sdev->nvm_function
		= kzalloc(sizeof(*sdev->nvm_function), GFP_KERNEL);
	if (!sdev->nvm_function) {
		pr_err("out of memory\n");
		return -ENOMEM;
	}

	rc = _bif_slave_read(sdev, func->function_pointer, buf, 8);
	if (rc) {
		pr_err("NVM function data read failed, rc=%d\n", rc);
		return rc;
	}

	sdev->nvm_function->nvm_pointer			= buf[0] << 8 | buf[1];
	sdev->nvm_function->slave_control_channel	= buf[2];
	sdev->nvm_function->write_buffer_size		= buf[3];
	sdev->nvm_function->nvm_base_address		= buf[4] << 8 | buf[5];
	sdev->nvm_function->nvm_size			= buf[6] << 8 | buf[7];

	/* Read NVM lock offset */
	rc = _bif_slave_read(sdev, sdev->nvm_function->nvm_pointer, buf, 2);
	if (rc) {
		pr_err("Slave memory read failed, rc=%d\n", rc);
		return rc;
	}

	sdev->nvm_function->nvm_lock_offset		= buf[0] << 8 | buf[1];

	INIT_LIST_HEAD(&sdev->nvm_function->object_list);

	/* Read object list */
	addr = sdev->nvm_function->nvm_base_address;
	rc = _bif_slave_read(sdev, addr, &object_type, 1);
	if (rc) {
		pr_err("Slave memory read failed, rc=%d\n", rc);
		return rc;
	}

	while (object_type != BIF_OBJ_END_OF_LIST) {
		object = kzalloc(sizeof(*object), GFP_KERNEL);
		if (!object) {
			pr_err("out of memory\n");
			rc = -ENOMEM;
			goto free_data;
		}
		list_add_tail(&object->list, &sdev->nvm_function->object_list);

		rc = _bif_slave_read(sdev, addr + 1, buf + 1, 5);
		if (rc) {
			pr_err("Slave memory read of object header failed; addr=0x%04X, len=%d, rc=%d\n",
				addr + 1, 5, rc);
			goto free_data;
		}

		object->addr		= addr;
		object->type		= object_type;
		object->version		= buf[1];
		object->manufacturer_id	= buf[2] << 8 | buf[3];
		object->length		= buf[4] << 8 | buf[5];

		if ((object->addr + object->length)
		    > (sdev->nvm_function->nvm_base_address
				+ sdev->nvm_function->nvm_size)) {
			pr_warn("warning: BIF slave object is not formatted correctly; NVM base=0x%04X, NVM len=%d, object addr=0x%04X, object len=%d\n",
				sdev->nvm_function->nvm_base_address,
				sdev->nvm_function->nvm_size,
				object->addr,
				object->length);
			/* Limit object size to remaining NVM size. */
			object->length = sdev->nvm_function->nvm_size
				+ sdev->nvm_function->nvm_base_address
				- object->addr;
		}

		/* Object header + CRC takes up 8 bytes. */
		data_len = object->length - 8;
		object->data = kmalloc(data_len, GFP_KERNEL);
		if (!object->data) {
			pr_err("out of memory\n");
			rc = -ENOMEM;
			goto free_data;
		}

		rc = _bif_slave_read(sdev, addr + 6, object->data, data_len);
		if (rc) {
			pr_err("Slave memory read of object data failed; addr=0x%04X, len=%d, rc=%d\n",
				addr + 6, data_len, rc);
			goto free_data;
		}

		if ((object->length + addr) >= (sdev->nvm_function->nvm_size
				+ sdev->nvm_function->nvm_base_address))
			read_size = 2;
		else
			read_size = 3;
		rc = _bif_slave_read(sdev, addr + 6 + data_len, buf, read_size);
		if (rc) {
			pr_err("Slave memory read of object CRC failed; addr=0x%04X, len=%d, rc=%d\n",
				addr + 6 + data_len, read_size, rc);
			goto free_data;
		}

		object->crc = buf[0] << 8 | buf[1];
		object_type = (read_size == 3) ? buf[2] : BIF_OBJ_END_OF_LIST;
		sdev->nvm_function->object_count++;

		crc = bif_object_crc_ccitt(object);
		if (crc != object->crc)
			pr_info("BIF object at addr=0x%04X has invalid CRC; crc calc=0x%04X, crc exp=0x%04X\n",
				object->addr, crc, object->crc);

		addr += object->length;
	}

	return rc;

free_data:
	list_for_each_entry_safe(object, temp,
				&sdev->nvm_function->object_list, list) {
		list_del(&object->list);
		kfree(object->data);
		kfree(object);
	}
	kfree(sdev->nvm_function);
	sdev->nvm_function = NULL;
	return rc;
}

static int bif_parse_slave_data(struct bif_slave_dev *sdev)
{
	int rc = 0;
	u8 buf[10];
	u8 *func_buf;
	struct bif_ddb_l2_data *func;
	int function_count, i;

	rc = _bif_slave_read(sdev, BIF_DDB_L1_BASE_ADDR, buf, 10);
	if (rc) {
		pr_err("DDB L1 data read failed, rc=%d\n", rc);
		return rc;
	}

	sdev->l1_data.revision		= buf[0];
	sdev->l1_data.level		= buf[1];
	sdev->l1_data.device_class	= buf[2] << 8 | buf[3];
	sdev->l1_data.manufacturer_id	= buf[4] << 8 | buf[5];
	sdev->l1_data.product_id	= buf[6] << 8 | buf[7];
	sdev->l1_data.length		= buf[8] << 8 | buf[9];

	function_count = sdev->l1_data.length / 4;
	if (sdev->l1_data.length % 4) {
		pr_err("Function directory length=%d is invalid\n",
				sdev->l1_data.length);
		return -EPROTO;
	}

	/* No DDB L2 function directory */
	if (function_count == 0)
		return 0;

	func_buf = kmalloc(sdev->l1_data.length, GFP_KERNEL);
	if (!func_buf) {
		pr_err("out of memory\n");
		return -ENOMEM;
	}

	sdev->function_directory = kzalloc(
		function_count * sizeof(struct bif_ddb_l2_data), GFP_KERNEL);
	if (!sdev->function_directory) {
		pr_err("out of memory\n");
		return -ENOMEM;
	}

	rc = _bif_slave_read(sdev, BIF_DDB_L2_BASE_ADDR, func_buf,
				sdev->l1_data.length);
	if (rc) {
		pr_err("DDB L2 data read failed, rc=%d\n", rc);
		return rc;
	}

	for (i = 0; i < function_count; i++) {
		func = &sdev->function_directory[i];
		func->function_type	= func_buf[i * 4];
		func->function_version	= func_buf[i * 4 + 1];
		func->function_pointer	= func_buf[i * 4 + 2] << 8
					  | func_buf[i * 4 + 3];
		rc = bif_initialize_protocol_function(sdev, func);
		if (rc)
			goto done;
		rc = bif_initialize_slave_control_function(sdev, func);
		if (rc)
			goto done;
		rc = bif_initialize_nvm_function(sdev, func);
		if (rc)
			goto done;
	}
done:
	kfree(func_buf);
	return rc;
}

static int bif_add_secondary_slaves(struct bif_slave_dev *primary_slave)
{
	int rc = 0;
	int data_len, i;
	u16 crc;
	struct bif_slave_dev *sdev;
	struct bif_object *object;

	list_for_each_entry(object, &primary_slave->nvm_function->object_list,
				list) {
		if (object->type != BIF_OBJ_SEC_SLAVE)
			continue;

		data_len = object->length - 8;
		if (data_len % BIF_UNIQUE_ID_BYTE_LENGTH) {
			pr_info("Invalid secondary slave object found, addr=0x%04X, data len=%d\n",
				object->addr, data_len);
			continue;
		}

		crc = bif_object_crc_ccitt(object);
		if (crc != object->crc) {
			pr_info("BIF object at addr=0x%04X has invalid CRC; crc calc=0x%04X, crc exp=0x%04X\n",
				object->addr, crc, object->crc);
			continue;
		}

		for (i = 0; i < data_len / BIF_UNIQUE_ID_BYTE_LENGTH; i++) {
			sdev = bif_add_slave(primary_slave->bdev);
			if (IS_ERR(sdev)) {
				rc = PTR_ERR(sdev);
				pr_err("bif_add_slave failed, rc=%d\n", rc);
				return rc;
			}
			memcpy(sdev->unique_id,
				&object->data[i * BIF_UNIQUE_ID_BYTE_LENGTH],
				BIF_UNIQUE_ID_BYTE_LENGTH);
			sdev->unique_id_bits_known = BIF_UNIQUE_ID_BIT_LENGTH;

			rc = bif_select_slave(sdev);
			if (rc) {
				pr_err("Could not select slave, rc=%d\n", rc);
				goto free_slave;
			}

			rc = bif_is_slave_selected(sdev->bdev);
			if (rc < 0) {
				pr_err("Transaction failed, rc=%d\n", rc);
				goto free_slave;
			} else if (rc == 1) {
				sdev->present = true;
				sdev->bdev->selected_sdev = sdev;
				rc = bif_parse_slave_data(sdev);
				if (rc) {
					pr_err("Failed to parse secondary slave data, rc=%d\n",
						rc);
					goto free_slave;
				}
			} else {
				sdev->present = false;
				sdev->bdev->selected_sdev = NULL;
			}
		}
	}

	return rc;

free_slave:
	bif_remove_slave(sdev);
	return rc;
}

/*
 * Performs UID search to identify all slaves attached to the bus. Assumes that
 * all necessary locks are held.
 */
static int bif_perform_uid_search(struct bif_ctrl_dev *bdev)
{
	struct bif_slave_dev *sdev;
	struct bif_slave_dev *new_slave;
	bool resp[2], resp_dilc;
	int i;
	int rc = 0;
	u8 cmd_probe[2] = {BIF_CMD_DIP0, BIF_CMD_DIP1};
	u8 cmd_enter[2] = {BIF_CMD_DIE0, BIF_CMD_DIE1};

	/*
	 * Iterate over all partially known UIDs adding new ones as they are
	 * found.
	 */
	list_for_each_entry(sdev, &bif_sdev_list, list) {
		/* Skip slaves with fully known UIDs. */
		if (sdev->unique_id_bits_known == BIF_UNIQUE_ID_BIT_LENGTH
		    || sdev->bdev != bdev)
			continue;

		/* Begin a new UID search. */
		rc = bdev->desc->ops->bus_transaction(bdev, BIF_TRANS_BC,
							BIF_CMD_DISS);
		if (rc) {
			pr_err("bus_transaction failed, rc=%d\n", rc);
			return rc;
		}

		/* Step through all known UID bits (MSB to LSB). */
		for (i = 0; i < sdev->unique_id_bits_known; i++) {
			rc = bdev->desc->ops->bus_transaction(bdev,
				BIF_TRANS_BC,
				cmd_enter[get_uid_bit(sdev->unique_id, i)]);
			if (rc) {
				pr_err("bus_transaction failed, rc=%d\n", rc);
				return rc;
			}
		}

		/* Step through unknown UID bits. */
		for (i = sdev->unique_id_bits_known;
				i < BIF_UNIQUE_ID_BIT_LENGTH; i++) {
			rc = bdev->desc->ops->bus_transaction_query(bdev,
				BIF_TRANS_BC, cmd_probe[0], &resp[0]);
			if (rc) {
				pr_err("bus_transaction failed, rc=%d\n", rc);
				return rc;
			}

			rc = bdev->desc->ops->bus_transaction_query(bdev,
				BIF_TRANS_BC, cmd_probe[1], &resp[1]);
			if (rc) {
				pr_err("bus_transaction failed, rc=%d\n", rc);
				return rc;
			}

			if (resp[0] && resp[1]) {
				/* Create an entry for the new UID branch. */
				new_slave = bif_add_slave(bdev);
				if (IS_ERR(new_slave)) {
					rc = PTR_ERR(sdev);
					pr_err("bif_add_slave failed, rc=%d\n",
						rc);
					return rc;
				}
				memcpy(new_slave->unique_id, sdev->unique_id,
					BIF_UNIQUE_ID_BYTE_LENGTH);
				new_slave->bdev = sdev->bdev;

				set_uid_bit(sdev->unique_id, i, 0);
				sdev->unique_id_bits_known = i + 1;

				set_uid_bit(new_slave->unique_id, i, 1);
				new_slave->unique_id_bits_known = i + 1;
			} else if (resp[0]) {
				set_uid_bit(sdev->unique_id, i, 0);
				sdev->unique_id_bits_known = i + 1;
			} else if (resp[1]) {
				set_uid_bit(sdev->unique_id, i, 1);
				sdev->unique_id_bits_known = i + 1;
			} else {
				pr_debug("no bus query response received\n");
				rc = -ENXIO;
				return rc;
			}

			rc = bdev->desc->ops->bus_transaction(bdev,
				BIF_TRANS_BC, cmd_enter[resp[0] ? 0 : 1]);
			if (rc) {
				pr_err("bus_transaction failed, rc=%d\n", rc);
				return rc;
			}
		}

		rc = bdev->desc->ops->bus_transaction_query(bdev,
			BIF_TRANS_BC, BIF_CMD_DILC, &resp_dilc);
		if (rc) {
			pr_err("bus_transaction failed, rc=%d\n", rc);
			return rc;
		}

		if (resp_dilc) {
			sdev->present = true;
			sdev->bdev->selected_sdev = sdev;
			rc = bif_parse_slave_data(sdev);
			if (rc) {
				pr_err("Failed to parse secondary slave data, rc=%d\n",
					rc);
				return rc;
			}
		} else {
			pr_err("Slave failed to respond to DILC bus command; its UID is thus unverified.\n");
			sdev->unique_id_bits_known = 0;
			rc = -ENXIO;
			return rc;
		}
	}

	return rc;
}

/*
 * Removes slaves from the bif_sdev_list which have the same UID as previous
 * slaves in the list.
 */
static int bif_remove_duplicate_slaves(struct bif_ctrl_dev *bdev)
{
	struct bif_slave_dev *sdev;
	struct bif_slave_dev *last_slave;
	struct bif_slave_dev *temp;

	list_for_each_entry_safe(last_slave, temp, &bif_sdev_list, list) {
		list_for_each_entry(sdev, &bif_sdev_list, list) {
			if (last_slave == sdev) {
				break;
			} else if (memcmp(last_slave->unique_id,
					sdev->unique_id,
					BIF_UNIQUE_ID_BYTE_LENGTH) == 0) {
				bif_remove_slave(last_slave);
				break;
			}
		}
	}

	return 0;
}

static int bif_add_all_slaves(struct bif_ctrl_dev *bdev)
{
	struct bif_slave_dev *sdev;
	int rc = 0;
	int i;
	bool has_slave = false, is_primary_slave = false;

	mutex_lock(&bif_sdev_list_mutex);
	mutex_lock(&bdev->mutex);

	list_for_each_entry(sdev, &bif_sdev_list, list) {
		if (sdev->bdev == bdev) {
			has_slave = true;
			break;
		}
	}

	if (!has_slave) {
		/* Create a single empty slave to start the search algorithm. */
		sdev = bif_add_slave(bdev);
		if (IS_ERR(sdev)) {
			rc = PTR_ERR(sdev);
			pr_err("bif_add_slave failed, rc=%d\n", rc);
			goto out;
		}

		for (i = 0; i < BIF_TRANSACTION_RETRY_COUNT; i++) {
			/* Attempt to select primary slave in battery pack. */
			rc = bdev->desc->ops->bus_transaction(bdev,
				BIF_TRANS_SDA, BIF_PRIMARY_SLAVE_DEV_ADR);
			if (rc == 0)
				break;
		}
		if (rc) {
			pr_err("BIF bus_transaction failed, rc=%d\n", rc);
			goto out;
		}

		/* Check if a slave is selected. */
		rc = bif_is_slave_selected(bdev);
		if (rc < 0) {
			pr_err("BIF bus_transaction failed, rc=%d\n", rc);
			goto out;
		} else {
			is_primary_slave = rc;
		}
	}

	if (is_primary_slave) {
		pr_debug("Using primary slave at DEV_ADR==0x%02X\n",
			BIF_PRIMARY_SLAVE_DEV_ADR);
		sdev->bdev->selected_sdev = sdev;
		sdev->present = true;
		sdev->slave_addr = BIF_PRIMARY_SLAVE_DEV_ADR;
		rc = bif_parse_slave_data(sdev);
		if (rc) {
			pr_err("Failed to parse primary slave data, rc=%d\n",
				rc);
			goto out;
		}
		rc = bif_add_secondary_slaves(sdev);
		if (rc) {
			pr_err("Failed to add secondary slaves, rc=%d\n", rc);
			goto out;
		}
	} else {
		pr_debug("Falling back on full UID search.\n");
		for (i = 0; i < BIF_TRANSACTION_RETRY_COUNT; i++) {
			rc = bif_perform_uid_search(bdev);
			if (rc == 0)
				break;
		}
		if (rc) {
			pr_debug("BIF UID search failed, rc=%d\n", rc);
			goto out;
		}
	}

	bif_remove_duplicate_slaves(bdev);

	mutex_unlock(&bdev->mutex);
	mutex_unlock(&bif_sdev_list_mutex);

	return rc;

out:
	mutex_unlock(&bdev->mutex);
	mutex_unlock(&bif_sdev_list_mutex);
	pr_debug("BIF slave search failed, rc=%d\n", rc);
	return rc;
}

static int bif_add_known_slave(struct bif_ctrl_dev *bdev, u8 slave_addr)
{
	struct bif_slave_dev *sdev;
	int rc = 0;
	int i;

	for (i = 0; i < BIF_TRANSACTION_RETRY_COUNT; i++) {
		/* Attempt to select the slave. */
		rc = bdev->desc->ops->bus_transaction(bdev, BIF_TRANS_SDA,
							slave_addr);
		if (rc == 0)
			break;
	}
	if (rc) {
		pr_err("BIF bus_transaction failed, rc=%d\n", rc);
		return rc;
	}

	/* Check if a slave is selected. */
	rc = bif_is_slave_selected(bdev);
	if (rc < 0) {
		pr_err("BIF bus_transaction failed, rc=%d\n", rc);
		return rc;
	}

	sdev = bif_add_slave(bdev);
	if (IS_ERR(sdev)) {
		rc = PTR_ERR(sdev);
		pr_err("bif_add_slave failed, rc=%d\n", rc);
		return rc;
	}

	sdev->bdev->selected_sdev = sdev;
	sdev->present = true;
	sdev->slave_addr = slave_addr;
	rc = bif_parse_slave_data(sdev);
	if (rc) {
		pr_err("Failed to parse slave data, addr=0x%02X, rc=%d\n",
			slave_addr, rc);
		return rc;
	}

	return rc;
}

static int bif_add_known_slaves_from_dt(struct bif_ctrl_dev *bdev,
					struct device_node *of_node)
{
	int len = 0;
	int rc, i;
	u32 addr;
	const __be32 *val;

	mutex_lock(&bif_sdev_list_mutex);
	mutex_lock(&bdev->mutex);

	val = of_get_property(of_node, "qcom,known-device-addresses", &len);
	len /= sizeof(u32);
	if (val && len == 0) {
		pr_err("qcom,known-device-addresses property is invalid\n");
		rc = -EINVAL;
		goto out;
	}

	for (i = 0; i < len; i++) {
		addr = be32_to_cpup(val++);
		if (addr == 0x00 || addr > 0xFF) {
			rc = -EINVAL;
			pr_err("qcom,known-device-addresses property contains invalid address=0x%X\n",
				addr);
			goto out;
		}
		rc = bif_add_known_slave(bdev, addr);
		if (rc) {
			pr_err("bif_add_known_slave() failed, rc=%d\n", rc);
			goto out;
		}
	}

out:
	if (len > 0)
		bif_remove_duplicate_slaves(bdev);

	mutex_unlock(&bdev->mutex);
	mutex_unlock(&bif_sdev_list_mutex);

	return rc;
}

/*
 * Programs a device address for the specified slave in order to simplify
 * slave selection in the future.
 */
static int bif_assign_slave_dev_addr(struct bif_slave_dev *sdev, u8 dev_addr)
{
	int rc;
	u16 addr;

	if (!sdev->protocol_function) {
		pr_err("Protocol function not present; cannot set device address.\n");
		return -ENODEV;
	}

	addr = PROTOCOL_FUNC_DEV_ADR_ADDR(
			sdev->protocol_function->protocol_pointer);

	rc = _bif_slave_write(sdev, addr, &dev_addr, 1);
	if (rc)
		pr_err("Failed to set slave device address.\n");
	else
		sdev->slave_addr = dev_addr;

	return rc;
}

/* Assigns a unique device address to all slaves which do not have one. */
static int bif_assign_all_slaves_dev_addr(struct bif_ctrl_dev *bdev)
{
	struct bif_slave_dev *sdev;
	struct bif_slave_dev *sibling;
	bool duplicate;
	int rc = 0;
	u8 dev_addr, first_dev_addr;

	mutex_lock(&bif_sdev_list_mutex);
	mutex_lock(&bdev->mutex);

	first_dev_addr = next_dev_addr;
	/*
	 * Iterate over all partially known UIDs adding new ones as they are
	 * found.
	 */
	list_for_each_entry(sdev, &bif_sdev_list, list) {
		/*
		 * Skip slaves without known UIDs, which already have a device
		 * address or which aren't present.
		 */
		if (sdev->unique_id_bits_known != BIF_UNIQUE_ID_BIT_LENGTH
		    || sdev->slave_addr != 0x00 || !sdev->present)
			continue;

		do {
			dev_addr = next_dev_addr;
			duplicate = false;
			list_for_each_entry(sibling, &bif_sdev_list, list) {
				if (sibling->slave_addr == dev_addr) {
					duplicate = true;
					break;
				}
			}

			next_dev_addr = dev_addr + 1;
		} while (duplicate && (next_dev_addr != first_dev_addr));

		if (next_dev_addr == first_dev_addr) {
			pr_err("No more BIF slave device addresses available.\n");
			rc = -ENODEV;
			goto out;
		}

		rc =  bif_assign_slave_dev_addr(sdev, dev_addr);
		if (rc) {
			pr_err("Failed to set slave address.\n");
			goto out;
		}
	}

	mutex_unlock(&bdev->mutex);
	mutex_unlock(&bif_sdev_list_mutex);

	return rc;

out:
	mutex_unlock(&bdev->mutex);
	mutex_unlock(&bif_sdev_list_mutex);
	pr_err("BIF slave device address setting failed, rc=%d\n", rc);
	return rc;
}

/**
 * bdev_get_drvdata() - get the private BIF controller driver data
 * @bdev:	BIF controller device pointer
 */
void *bdev_get_drvdata(struct bif_ctrl_dev *bdev)
{
	return bdev->driver_data;
}
EXPORT_SYMBOL(bdev_get_drvdata);

static const char * const battery_label[] = {
	"unknown",
	"none",
	"special 1",
	"special 2",
	"special 3",
	"low cost",
	"smart",
};

static const char *bif_get_battery_pack_type(int rid_ohm)
{
	const char *label = battery_label[0];

	if (rid_ohm > BIF_BATT_RID_SMART_MAX)
		label = battery_label[1];
	else if (rid_ohm >= BIF_BATT_RID_SMART_MIN)
		label = battery_label[6];
	else if (rid_ohm >= BIF_BATT_RID_LOW_COST_MIN
			&& rid_ohm <= BIF_BATT_RID_LOW_COST_MAX)
		label = battery_label[5];
	else if (rid_ohm >= BIF_BATT_RID_SPECIAL3_MIN
			&& rid_ohm <= BIF_BATT_RID_SPECIAL3_MAX)
		label = battery_label[4];
	else if (rid_ohm >= BIF_BATT_RID_SPECIAL2_MIN
			&& rid_ohm <= BIF_BATT_RID_SPECIAL2_MAX)
		label = battery_label[3];
	else if (rid_ohm >= BIF_BATT_RID_SPECIAL1_MIN
			&& rid_ohm <= BIF_BATT_RID_SPECIAL1_MAX)
		label = battery_label[2];

	return label;
}

/**
 * bif_ctrl_register() - register a BIF controller with the BIF framework
 * @bif_desc:		Pointer to BIF controller descriptor
 * @dev:		Device pointer of the BIF controller
 * @driver_data:	Private driver data to associate with the BIF controller
 * @of_node		Pointer to the device tree node of the BIF controller
 *
 * Returns a BIF controller device pointer for the controller if registration
 * is successful or an ERR_PTR if an error occurred.
 */
struct bif_ctrl_dev *bif_ctrl_register(struct bif_ctrl_desc *bif_desc,
	struct device *dev, void *driver_data, struct device_node *of_node)
{
	struct bif_ctrl_dev *bdev = ERR_PTR(-EINVAL);
	struct bif_slave_dev *sdev;
	bool battery_present = false;
	bool slaves_present = false;
	int rc, rid_ohm;

	if (!bif_desc) {
		pr_err("Invalid bif_desc specified\n");
		return bdev;
	} else if (!bif_desc->name) {
		pr_err("BIF name missing\n");
		return bdev;
	} else if (!bif_desc->ops) {
		pr_err("BIF operations missing\n");
		return bdev;
	} else if (!bif_desc->ops->bus_transaction
			|| !bif_desc->ops->bus_transaction_query
			|| !bif_desc->ops->bus_transaction_read
			|| !bif_desc->ops->get_bus_state
			|| !bif_desc->ops->set_bus_state) {
		pr_err("BIF operation callback function(s) missing\n");
		return bdev;
	}

	bdev = kzalloc(sizeof(struct bif_ctrl_dev), GFP_KERNEL);
	if (bdev == NULL) {
		pr_err("Memory allocation failed for bif_ctrl_dev\n");
		return ERR_PTR(-ENOMEM);
	}

	mutex_init(&bdev->mutex);
	INIT_LIST_HEAD(&bdev->list);
	INIT_DELAYED_WORK(&bdev->enter_irq_mode_work, bif_enter_irq_mode_work);
	bdev->desc			= bif_desc;
	bdev->ctrl_dev			= dev;
	bdev->driver_data		= driver_data;
	bdev->irq_mode_delay_jiffies	= 2;

	mutex_lock(&bif_ctrl_list_mutex);
	list_add_tail(&bdev->list, &bif_ctrl_list);
	mutex_unlock(&bif_ctrl_list_mutex);

	rc = bif_add_all_slaves(bdev);
	if (rc)
		pr_debug("Search for all slaves failed, rc=%d\n", rc);
	rc = bif_add_known_slaves_from_dt(bdev, of_node);
	if (rc)
		pr_err("Adding slaves based on device tree addressed failed, rc=%d.\n",
			rc);
	rc = bif_assign_all_slaves_dev_addr(bdev);
	if (rc)
		pr_err("Failed to set slave device address, rc=%d\n", rc);

	bif_print_slaves();

	if (bdev->desc->ops->get_battery_presence) {
		rc = bdev->desc->ops->get_battery_presence(bdev);
		if (rc < 0) {
			pr_err("Could not determine battery presence, rc=%d\n",
				rc);
		} else {
			battery_present = rc;
			pr_info("Battery pack present = %c\n", rc ? 'Y' : 'N');
		}
	}

	if (bdev->desc->ops->get_battery_rid) {
		rid_ohm = bdev->desc->ops->get_battery_rid(bdev);
		if (rid_ohm >= 0)
			pr_info("Battery pack type = %s (Rid=%d ohm)\n",
				bif_get_battery_pack_type(rid_ohm), rid_ohm);
		else
			pr_err("Could not read Rid, rc=%d\n", rid_ohm);
	}

	list_for_each_entry(sdev, &bif_sdev_list, list) {
		if (sdev->present) {
			battery_present = true;
			slaves_present = true;
			break;
		}
	}

	BLOCKING_INIT_NOTIFIER_HEAD(&bdev->bus_change_notifier);

	/* Disable the BIF bus master if no slaves are found. */
	if (!slaves_present) {
		rc = bdev->desc->ops->set_bus_state(bdev,
			BIF_BUS_STATE_MASTER_DISABLED);
		if (rc < 0)
			pr_err("Could not disble BIF master, rc=%d\n", rc);
	}

	if (battery_present) {
		bdev->battery_present = true;
		rc = blocking_notifier_call_chain(&bdev->bus_change_notifier,
			BIF_BUS_EVENT_BATTERY_INSERTED, bdev);
		if (rc)
			pr_err("Call chain noification failed, rc=%d\n", rc);
	}

	return bdev;
}
EXPORT_SYMBOL(bif_ctrl_register);

/**
 * bif_ctrl_unregister() - unregisters a BIF controller
 * @bdev:	BIF controller device pointer
 */
void bif_ctrl_unregister(struct bif_ctrl_dev *bdev)
{
	if (bdev) {
		mutex_lock(&bif_ctrl_list_mutex);
		list_del(&bdev->list);
		mutex_unlock(&bif_ctrl_list_mutex);
	}
}
EXPORT_SYMBOL(bif_ctrl_unregister);
