Merge "msm: krait-regulator: use phase management for v2"
diff --git a/Documentation/devicetree/bindings/bif/bif.txt b/Documentation/devicetree/bindings/bif/bif.txt
new file mode 100644
index 0000000..c4ff08b
--- /dev/null
+++ b/Documentation/devicetree/bindings/bif/bif.txt
@@ -0,0 +1,22 @@
+BIF (Battery Interface) Controllers
+
+Optional properties:
+- qcom,known-device-addresses: Specifies a list of integers which correspond to
+ the 8-bit BIF bus device addresses of BIF slaves
+ found on the target.
+
+BIF Consumers
+
+Optional properties:
+- qcom,bif-ctrl: phandle of parent BIF controller device node
+
+Example:
+ foo_ctrl: foo-controller {
+ ...
+ qcom,known-device-addresses = <0x80, 0x81>;
+ };
+
+ bar-consumer {
+ ...
+ qcom,bif-ctrl = <&foo_ctrl>;
+ };
diff --git a/Documentation/devicetree/bindings/memory.txt b/Documentation/devicetree/bindings/memory.txt
new file mode 100644
index 0000000..74e0476
--- /dev/null
+++ b/Documentation/devicetree/bindings/memory.txt
@@ -0,0 +1,101 @@
+* Memory binding
+
+The /memory node provides basic information about the address and size
+of the physical memory. This node is usually filled or updated by the
+bootloader, depending on the actual memory configuration of the given
+hardware.
+
+The memory layout is described by the folllowing node:
+
+memory {
+ reg = <(baseaddr1) (size1)
+ (baseaddr2) (size2)
+ ...
+ (baseaddrN) (sizeN)>;
+};
+
+baseaddrX: the base address of the defined memory bank
+sizeX: the size of the defined memory bank
+
+More than one memory bank can be defined.
+
+
+* Memory regions
+
+In /memory node one can create additional nodes describing particular
+memory regions, usually for the special usage by various device drivers.
+A good example are contiguous memory allocations or memory sharing with
+other operating system on the same hardware board. Those special memory
+regions might depend on the board configuration and devices used on the
+target system.
+
+Parameters for each memory region can be encoded into the device tree
+wit the following convention:
+
+(name): region@(base-address) {
+ reg = <(baseaddr) (size)>;
+ (linux,contiguous-region);
+ (linux,default-contiguous-region);
+};
+
+name: an name given to the defined region.
+base-address: the base address of the defined region.
+size: the size of the memory region.
+linux,contiguous-region: property indicating that the defined memory
+ region is used for contiguous memory allocations,
+ Linux specific (optional)
+linux,default-contiguous-region: property indicating that the region
+ is the default region for all contiguous memory
+ allocations, Linux specific (optional)
+
+
+* Device nodes
+
+Once the regions in the /memory node are defined, they can be assigned
+to device some device nodes for their special use. The following
+properties are defined:
+
+linux,contiguous-region = <&phandle>;
+ This property indicates that the device driver should use the
+ memory region pointed by the given phandle.
+
+
+* Example:
+
+This example defines a memory consisting of 4 memory banks. 2 contiguous
+regions are defined for Linux kernel, one default of all device drivers
+(named contig_mem, placed at 0x72000000, 64MiB) and one dedicated to the
+framebuffer device (named display_mem, placed at 0x78000000, 16MiB). The
+display_mem region is then assigned to fb@12300000 device for contiguous
+memory allocation with Linux kernel drivers.
+
+The reason for creating a separate region for framebuffer device is to
+match the framebuffer address of from configuration done by bootloader,
+so once Linux kernel drivers starts, no glitches on the displayed boot
+logo appears.
+
+/ {
+ /* ... */
+ memory {
+ reg = <0x40000000 0x10000000
+ 0x50000000 0x10000000
+ 0x60000000 0x10000000
+ 0x70000000 0x10000000>;
+
+ contig_mem: region@72000000 {
+ linux,contiguous-region;
+ linux,default-contiguous-region;
+ reg = <0x72000000 0x4000000>;
+ };
+
+ display_mem: region@78000000 {
+ linux,contiguous-region;
+ reg = <0x78000000 0x1000000>;
+ };
+ };
+
+ fb@12300000 {
+ linux,contiguous-region = <&display_mem>;
+ status = "okay";
+ };
+};
diff --git a/arch/arm/boot/dts/skeleton.dtsi b/arch/arm/boot/dts/skeleton.dtsi
index b41d241..f9988cd 100644
--- a/arch/arm/boot/dts/skeleton.dtsi
+++ b/arch/arm/boot/dts/skeleton.dtsi
@@ -9,5 +9,10 @@
#size-cells = <1>;
chosen { };
aliases { };
- memory { device_type = "memory"; reg = <0 0>; };
+ memory {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ device_type = "memory";
+ reg = <0 0>;
+ };
};
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index 952171c..5c03630 100644
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -356,10 +356,6 @@
CONFIG_SND_USB_AUDIO=y
CONFIG_SND_SOC=y
CONFIG_SND_SOC_MSM8974=y
-CONFIG_UHID=y
-CONFIG_HID_APPLE=y
-CONFIG_HID_MAGICMOUSE=y
-CONFIG_HID_MICROSOFT=y
CONFIG_USB_SUSPEND=y
CONFIG_USB_XHCI_HCD=y
CONFIG_USB_EHCI_HCD=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index a3a4487..faa0471 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -364,10 +364,6 @@
CONFIG_SND_USB_AUDIO=y
CONFIG_SND_SOC=y
CONFIG_SND_SOC_MSM8974=y
-CONFIG_UHID=y
-CONFIG_HID_APPLE=y
-CONFIG_HID_MAGICMOUSE=y
-CONFIG_HID_MICROSOFT=y
CONFIG_USB_SUSPEND=y
CONFIG_USB_XHCI_HCD=y
CONFIG_USB_EHCI_HCD=y
diff --git a/drivers/Kconfig b/drivers/Kconfig
index a73d713..adead10 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -150,4 +150,6 @@
source "drivers/coresight/Kconfig"
+source "drivers/bif/Kconfig"
+
endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index f461e83..d55b035 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -142,3 +142,5 @@
obj-$(CONFIG_MOBICORE_SUPPORT) += gud/
obj-$(CONFIG_CORESIGHT) += coresight/
+
+obj-$(CONFIG_BIF) += bif/
diff --git a/drivers/base/dma-contiguous.c b/drivers/base/dma-contiguous.c
index 1937db8..cd341e8 100644
--- a/drivers/base/dma-contiguous.c
+++ b/drivers/base/dma-contiguous.c
@@ -24,6 +24,9 @@
#include <linux/memblock.h>
#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/of_fdt.h>
+#include <linux/of_platform.h>
#include <linux/mm.h>
#include <linux/mutex.h>
#include <linux/page-isolation.h>
@@ -181,6 +184,35 @@
return ERR_PTR(ret);
}
+/*****************************************************************************/
+
+#ifdef CONFIG_OF
+int __init cma_fdt_scan(unsigned long node, const char *uname,
+ int depth, void *data)
+{
+ phys_addr_t base, size;
+ unsigned long len;
+ __be32 *prop;
+
+ if (strncmp(uname, "region@", 7) != 0 || depth != 2 ||
+ !of_get_flat_dt_prop(node, "contiguous-region", NULL))
+ return 0;
+
+ prop = of_get_flat_dt_prop(node, "reg", &len);
+ if (!prop || (len != 2 * sizeof(unsigned long)))
+ return 0;
+
+ base = be32_to_cpu(prop[0]);
+ size = be32_to_cpu(prop[1]);
+
+ pr_info("Found %s, memory base %lx, size %ld MiB\n", uname,
+ (unsigned long)base, (unsigned long)size / SZ_1M);
+ dma_contiguous_reserve_area(size, &base, 0);
+
+ return 0;
+}
+#endif
+
/**
* dma_contiguous_reserve() - reserve area for contiguous memory handling
* @limit: End address of the reserved memory (optional, 0 for any).
@@ -219,6 +251,9 @@
if (dma_contiguous_reserve_area(sel_size, &base, limit) == 0)
dma_contiguous_def_base = base;
}
+#ifdef CONFIG_OF
+ of_scan_flat_dt(cma_fdt_scan, NULL);
+#endif
};
/**
@@ -323,6 +358,40 @@
return 0;
}
+#ifdef CONFIG_OF
+static void cma_assign_device_from_dt(struct device *dev)
+{
+ struct device_node *node;
+ struct cma *cma;
+ u32 value;
+
+ node = of_parse_phandle(dev->of_node, "linux,contiguous-region", 0);
+ if (!node)
+ return;
+ if (of_property_read_u32(node, "reg", &value) && !value)
+ return;
+ cma = cma_get_area(value);
+ if (!cma)
+ return;
+
+ dev_set_cma_area(dev, cma);
+ pr_info("Assigned CMA region at %lx to %s device\n", (unsigned long)value, dev_name(dev));
+}
+
+static int cma_device_init_notifier_call(struct notifier_block *nb,
+ unsigned long event, void *data)
+{
+ struct device *dev = data;
+ if (event == BUS_NOTIFY_ADD_DEVICE && dev->of_node)
+ cma_assign_device_from_dt(dev);
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block cma_dev_init_nb = {
+ .notifier_call = cma_device_init_notifier_call,
+};
+#endif
+
static int __init cma_init_reserved_areas(void)
{
struct cma *cma;
@@ -344,6 +413,9 @@
dev_set_cma_area(cma_maps[i].dev, cma);
}
+#ifdef CONFIG_OF
+ bus_register_notifier(&platform_bus_type, &cma_dev_init_nb);
+#endif
return 0;
}
core_initcall(cma_init_reserved_areas);
diff --git a/drivers/bif/Kconfig b/drivers/bif/Kconfig
new file mode 100644
index 0000000..502b92b
--- /dev/null
+++ b/drivers/bif/Kconfig
@@ -0,0 +1,12 @@
+#
+# BIF framework and drivers
+#
+menuconfig BIF
+ bool "MIPI-BIF support"
+ select CRC_CCITT
+ select BITREVERSE
+ help
+ MIPI-BIF (battery interface) is a one-wire serial interface between a
+ host master device and one or more slave devices which are located in
+ a battery pack or also on the host. Enabling this option allows for
+ BIF consumer drivers to issue transactions via BIF controller drivers.
diff --git a/drivers/bif/Makefile b/drivers/bif/Makefile
new file mode 100644
index 0000000..02528c1
--- /dev/null
+++ b/drivers/bif/Makefile
@@ -0,0 +1,4 @@
+#
+# Makefile for kernel BIF framework.
+#
+obj-$(CONFIG_BIF) += bif-core.o
diff --git a/drivers/bif/bif-core.c b/drivers/bif/bif-core.c
new file mode 100644
index 0000000..e11e6ba4
--- /dev/null
+++ b/drivers/bif/bif-core.c
@@ -0,0 +1,2934 @@
+/* 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\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);
+ 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_err("read_slave_registers failed, rc=%d\n", rc);
+ return rc;
+ }
+
+ 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_err("write_slave_registers failed, rc=%d\n", rc);
+ return rc;
+ }
+
+ 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;
+}
+
+/* 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);
+}
+
+static int bif_check_task(struct bif_slave *slave, unsigned int task)
+{
+ if (IS_ERR_OR_NULL(slave)) {
+ pr_err("Invalid slave handle.\n");
+ return -EINVAL;
+ } else if (!slave->sdev->bdev) {
+ pr_err("BIF controller has been removed.\n");
+ return -ENXIO;
+ } else if (!slave->sdev->slave_ctrl_function
+ || slave->sdev->slave_ctrl_function->task_count == 0) {
+ pr_err("BIF slave does not support slave control.\n");
+ return -ENODEV;
+ } else if (task >= slave->sdev->slave_ctrl_function->task_count) {
+ pr_err("Requested task: %u greater than max: %u for this slave\n",
+ task, slave->sdev->slave_ctrl_function->task_count);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * 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, ®, 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, ®, 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, ®, 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, ®, 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, ®, 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, ®, 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_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;
+ 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);
+
+ /* Check the task busy state. */
+ addr = SLAVE_CTRL_FUNC_TASK_BUSY_ADDR(
+ slave->sdev->slave_ctrl_function->slave_ctrl_pointer, task);
+ rc = _bif_slave_read(slave->sdev, addr, ®, 1);
+ if (rc) {
+ pr_err("BIF slave register read failed, rc=%d\n", rc);
+ goto done;
+ }
+
+ rc = (reg & BIT(task % SLAVE_CTRL_TASKS_PER_SET)) ? 1 : 0;
+done:
+ 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, ®, 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, ®, 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);
+
+/*
+ * 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(const struct bif_ctrl *ctrl,
+ struct bif_slave_dev *sdev, const struct bif_match_criteria *criteria)
+{
+ int i, type, version;
+
+ 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)))
+ return true;
+ }
+ 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(const 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(const 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);
+
+/**
+ * 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_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;
+}
+
+/**
+ * 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);
+}
+
+/*
+ * 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;
+ 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];
+
+ 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;
+ }
+
+ /* Object type == 0x00 corresponds to the end of the object list. */
+ while (object_type != 0x00) {
+ 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;
+ }
+
+ rc = _bif_slave_read(sdev, addr + 6 + data_len, buf, 3);
+ if (rc) {
+ pr_err("Slave memory read of object CRC failed; addr=0x%04X, len=%d, rc=%d\n",
+ addr + 6 + data_len, 3, rc);
+ goto free_data;
+ }
+
+ object->crc = buf[0] << 8 | buf[1];
+ object_type = buf[2];
+ 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;
+ } 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);
+ } 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;
+ 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;
+ break;
+ }
+ }
+
+ BLOCKING_INIT_NOTIFIER_HEAD(&bdev->bus_change_notifier);
+
+ 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);
diff --git a/drivers/power/qpnp-bms.c b/drivers/power/qpnp-bms.c
index 85a310a..eb75475 100644
--- a/drivers/power/qpnp-bms.c
+++ b/drivers/power/qpnp-bms.c
@@ -670,10 +670,18 @@
#define SLEEP_CLK_HZ 32764
#define SECONDS_PER_HOUR 3600
-static s64 cc_uv_to_uvh(s64 cc_uv)
+static s64 cc_uv_to_pvh(s64 cc_uv)
{
- return div_s64(cc_uv * CC_READING_TICKS,
- SLEEP_CLK_HZ * SECONDS_PER_HOUR);
+ /* Note that it is necessary need to multiply by 1000000 to convert
+ * from uvh to pvh here.
+ * However, the maximum Coulomb Counter value is 2^35, which can cause
+ * an over flow.
+ * Multiply by 100000 first to perserve as much precision as possible
+ * then multiply by 10 after doing the division in order to avoid
+ * overflow on the maximum Coulomb Counter value.
+ */
+ return div_s64(cc_uv * CC_READING_TICKS * 100000,
+ SLEEP_CLK_HZ * SECONDS_PER_HOUR) * 10;
}
/**
@@ -688,7 +696,7 @@
*/
static int calculate_cc(struct qpnp_bms_chip *chip, int64_t cc)
{
- int64_t cc_voltage_uv, cc_uvh, cc_uah;
+ int64_t cc_voltage_uv, cc_pvh, cc_uah;
struct qpnp_iadc_calib calibration;
qpnp_iadc_get_gain_and_offset(&calibration);
@@ -702,9 +710,9 @@
calibration.gain_raw
- calibration.offset_raw);
pr_debug("cc_voltage_uv = %lld uv\n", cc_voltage_uv);
- cc_uvh = cc_uv_to_uvh(cc_voltage_uv);
- pr_debug("cc_uvh = %lld micro_volt_hour\n", cc_uvh);
- cc_uah = div_s64(cc_uvh * 1000000LL, chip->r_sense_uohm);
+ cc_pvh = cc_uv_to_pvh(cc_voltage_uv);
+ pr_debug("cc_pvh = %lld pvh\n", cc_pvh);
+ cc_uah = div_s64(cc_pvh, chip->r_sense_uohm);
/* cc_raw had 4 bits of extra precision.
By now it should be within 32 bit range */
return (int)cc_uah;
@@ -1474,16 +1482,12 @@
static int clamp_soc_based_on_voltage(struct qpnp_bms_chip *chip, int soc)
{
int rc, vbat_uv;
- struct qpnp_vadc_result result;
- rc = qpnp_vadc_read(VBAT_SNS, &result);
- if (rc) {
- pr_err("error reading vbat_sns adc channel = %d, rc = %d\n",
- VBAT_SNS, rc);
- return rc;
+ rc = get_battery_voltage(&vbat_uv);
+ if (rc < 0) {
+ pr_err("adc vbat failed err = %d\n", rc);
+ return soc;
}
-
- vbat_uv = (int)result.physical;
if (soc == 0 && vbat_uv > chip->v_cutoff_uv) {
pr_debug("clamping soc to 1, vbat (%d) > cutoff (%d)\n",
vbat_uv, chip->v_cutoff_uv);
@@ -1612,28 +1616,16 @@
return chip->calculated_soc;
}
-static int read_vbat(struct qpnp_bms_chip *chip)
-{
- int rc;
- struct qpnp_vadc_result result;
-
- rc = qpnp_vadc_read(VBAT_SNS, &result);
- if (rc) {
- pr_err("error reading vadc VBAT_SNS = %d, rc = %d\n",
- VBAT_SNS, rc);
- return rc;
- }
- pr_debug("read %duv from vadc\n", (int)result.physical);
- return (int)result.physical;
-}
-
static int calculate_soc_from_voltage(struct qpnp_bms_chip *chip)
{
int voltage_range_uv, voltage_remaining_uv, voltage_based_soc;
- int vbat_uv;
+ int rc, vbat_uv;
- vbat_uv = read_vbat(chip);
-
+ rc = get_battery_voltage(&vbat_uv);
+ if (rc < 0) {
+ pr_err("adc vbat failed err = %d\n", rc);
+ return rc;
+ }
voltage_range_uv = chip->max_voltage_uv - chip->v_cutoff_uv;
voltage_remaining_uv = vbat_uv - chip->v_cutoff_uv;
voltage_based_soc = voltage_remaining_uv * 100 / voltage_range_uv;
@@ -2467,7 +2459,12 @@
}
vbatt = 0;
- get_battery_voltage(&vbatt);
+ rc = get_battery_voltage(&vbatt);
+ if (rc) {
+ pr_err("error reading vbat_sns adc channel = %d, rc = %d\n",
+ VBAT_SNS, rc);
+ goto unregister_dc;
+ }
pr_info("probe success: soc =%d vbatt = %d ocv = %d r_sense_uohm = %u\n",
get_prop_bms_capacity(chip),
diff --git a/include/linux/bif/consumer.h b/include/linux/bif/consumer.h
new file mode 100644
index 0000000..e4c190e
--- /dev/null
+++ b/include/linux/bif/consumer.h
@@ -0,0 +1,613 @@
+/* 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.
+ */
+
+#ifndef _LINUX_BIF_CONSUMER_H_
+#define _LINUX_BIF_CONSUMER_H_
+
+#include <linux/bitops.h>
+#include <linux/kernel.h>
+#include <linux/notifier.h>
+
+#define BIF_DEVICE_ID_BYTE_LENGTH 8
+#define BIF_UNIQUE_ID_BYTE_LENGTH 10
+#define BIF_UNIQUE_ID_BIT_LENGTH 80
+
+#define BIF_PRIMARY_SLAVE_DEV_ADR 0x01
+
+/**
+ * enum bif_transaction - BIF master bus transaction types
+ * %BIF_TRANS_WD: Write data
+ * %BIF_TRANS_ERA: Extended register address
+ * %BIF_TRANS_WRA: Write register address
+ * %BIF_TRANS_RRA: Read register address
+ * %BIF_TRANS_BC: Bus command
+ * %BIF_TRANS_EDA: Extended device address
+ * %BIF_TRANS_SDA: Slave device address
+ *
+ * These values correspond to BIF word bits: BCF, bit 9, bit 8.
+ * BCF_n bit is inserted automatically.
+ */
+enum bif_transaction {
+ BIF_TRANS_WD = 0x00,
+ BIF_TRANS_ERA = 0x01,
+ BIF_TRANS_WRA = 0x02,
+ BIF_TRANS_RRA = 0x03,
+ BIF_TRANS_BC = 0x04,
+ BIF_TRANS_EDA = 0x05,
+ BIF_TRANS_SDA = 0x06,
+};
+
+/* BIF slave response components */
+#define BIF_SLAVE_RD_ACK 0x200
+#define BIF_SLAVE_RD_EOT 0x100
+#define BIF_SLAVE_RD_DATA 0x0FF
+#define BIF_SLAVE_RD_ERR 0x0FF
+#define BIF_SLAVE_TACK_ACK 0x200
+#define BIF_SLAVE_TACK_WCNT 0x0FF
+#define BIF_SLAVE_TACK_ERR 0x0FF
+
+/**
+ * enum bif_bus_command - MIPI defined bus commands to use in BC transaction
+ * %BIF_CMD_BRES: Bus reset of all slaves
+ * %BIF_CMD_PDWN: Put all slaves into power down mode
+ * %BIF_CMD_STBY: Put all slaves into standby mode
+ * %BIF_CMD_EINT: Enable interrupts for all slaves
+ * %BIF_CMD_ISTS: Poll interrupt status for all slaves. Expects BQ
+ * response if any slave has a pending interrupt.
+ * %BIF_CMD_RBL: Specify the burst read length for the next read
+ * transaction. Bits 3 to 0 should also be ORed on in
+ * order to specify the number of bytes to read.
+ * %BIF_CMD_RBE: Specify the extended burst read length for the next read
+ * transaction. Bits 3 to 0 should also be ORed on in
+ * order to specify the number of bytes to read. The burst
+ * read length for RBEy and RBLx = 16 * y + x.
+ * %BIF_CMD_DASM: Device activation stick mode. This keeps a slave
+ * selected if it would otherwise become unselected by the
+ * next transaction.
+ * %BIF_CMD_DISS: UID search start
+ * %BIF_CMD_DILC: UID length check. Expects BQ response if all 80 UID
+ * bits for a given slave have been entered.
+ * %BIF_CMD_DIE0: UID search enter 0
+ * %BIF_CMD_DIE1: UID search enter 1
+ * %BIF_CMD_DIP0: UID search probe 0
+ * %BIF_CMD_DIP1: UID search probe 1
+ * %BIF_CMD_DRES: Device reset of selected slaves
+ * %BIF_CMD_TQ: Transaction query; expects TACK response
+ * %BIF_CMD_AIO: Address increment off for the next transaction
+ *
+ * These values correspond to BIF word bits 7 to 0.
+ */
+enum bif_bus_command {
+ BIF_CMD_BRES = 0x00,
+ BIF_CMD_PDWN = 0x02,
+ BIF_CMD_STBY = 0x03,
+ BIF_CMD_EINT = 0x10,
+ BIF_CMD_ISTS = 0x11,
+ BIF_CMD_RBL = 0x20,
+ BIF_CMD_RBE = 0x30,
+ BIF_CMD_DASM = 0x40,
+ BIF_CMD_DISS = 0x80,
+ BIF_CMD_DILC = 0x81,
+ BIF_CMD_DIE0 = 0x84,
+ BIF_CMD_DIE1 = 0x85,
+ BIF_CMD_DIP0 = 0x86,
+ BIF_CMD_DIP1 = 0x87,
+ BIF_CMD_DRES = 0xC0,
+ BIF_CMD_TQ = 0xC2,
+ BIF_CMD_AIO = 0xC4,
+};
+
+/**
+ * struct bif_ddb_l1_data - MIPI defined L1 DDB data structure
+ * @revision: DDB version; should be 0x10 for DDB v1.0
+ * @level: DDB level support; should be 0x03 for DDB L1 and L2
+ * @device_class: MIPI device class; should be 0x0800
+ * @manufacturer_id: Manufacturer ID number allocated by MIPI
+ * @product_id: Manufacturer specified product ID number
+ * @length: Size of L2 function directory in bytes
+ */
+struct bif_ddb_l1_data {
+ u8 revision;
+ u8 level;
+ u16 device_class;
+ u16 manufacturer_id;
+ u16 product_id;
+ u16 length;
+};
+
+/**
+ * struct bif_ddb_l2_data - MIPI defined L2 DDB function data structure
+ * @function_type: Defines the type of the function. The type may be
+ * either MIPI or manufacturer defined.
+ * @function_version: Defines the version of the function. The version may
+ * be either MIPI or manufacturer defined.
+ * @function_pointer: Address in BIF slave memory where the register map for
+ * the function begins.
+ */
+struct bif_ddb_l2_data {
+ u8 function_type;
+ u8 function_version;
+ u16 function_pointer;
+};
+
+/**
+ * enum bif_mipi_function_type - MIPI defined DDB L2 function types
+ * %BIF_FUNC_PROTOCOL: Protocol function which provides access to core
+ * BIF communication features.
+ * %BIF_FUNC_SLAVE_CONTROL: Slave control function which provides control
+ * for BIF slave interrupts and tasks.
+ * %BIF_FUNC_TEMPERATURE: Temperature sensor function which provides a
+ * means to accurately read the battery temperature
+ * in a single-shot or periodic fashion.
+ * %BIF_FUNC_NVM: Non-volatile memory function which provides a
+ * means to store data onto a BIF slave that is
+ * non-volatile. Secondary slave objects are also
+ * found through the NVM function.
+ * %BIF_FUNC_AUTHENTICATION: Authentication function which provides a means
+ * to authenticate batteries. This function does
+ * not have a MIPI defined implimentation. Instead
+ * all aspects of the authentication function are
+ * left to the discretion of the manufacturer.
+ */
+enum bif_mipi_function_type {
+ BIF_FUNC_PROTOCOL = 0x01,
+ BIF_FUNC_SLAVE_CONTROL = 0x02,
+ BIF_FUNC_TEMPERATURE = 0x03,
+ BIF_FUNC_NVM = 0x04,
+ BIF_FUNC_AUTHENTICATION = 0x05,
+};
+
+#define BIF_DDB_L1_BASE_ADDR 0x0000
+#define BIF_DDB_L2_BASE_ADDR 0x000A
+
+/**
+ * enum bif_slave_error_code - MIPI defined BIF slave error codes
+ * %BIF_ERR_NONE: No error occurred
+ * %BIF_ERR_GENERAL: An unenumerated error occurred
+ * %BIF_ERR_PARITY: A Hamming-15 parity check failed for a word
+ * sent on the bus
+ * %BIF_ERR_INVERSION: More than 8 bits in a word were 1
+ * %BIF_ERR_BAD_LENGTH: Word had more or less than 17 bits
+ * %BIF_ERR_TIMING: Bit timing was violated in a word
+ * %BIF_ERR_UNKNOWN_CMD: Bus command was unknown to the slave
+ * %BIF_ERR_CMD_SEQ: Commands with ordering dependency were not
+ * sent in the right order
+ * %BIF_ERR_BUS_COLLISION: BCL was already low at the beginning of a new
+ * transaction
+ * %BIF_ERR_SLAVE_BUSY: Slave is busy and cannot respond
+ * %BIF_ERR_FATAL: Slave is in an unrecoverable error state and
+ * must be reset
+ *
+ * These values are present in the ERR portion of an RD or TACK slave response
+ * word. These values can also be found in the ERR_CODE register of the
+ * protocol function.
+ */
+enum bif_slave_error_code {
+ BIF_ERR_NONE = 0x00,
+ BIF_ERR_GENERAL = 0x10,
+ BIF_ERR_PARITY = 0x11,
+ BIF_ERR_INVERSION = 0x12,
+ BIF_ERR_BAD_LENGTH = 0x13,
+ BIF_ERR_TIMING = 0x14,
+ BIF_ERR_UNKNOWN_CMD = 0x15,
+ BIF_ERR_CMD_SEQ = 0x16,
+ BIF_ERR_BUS_COLLISION = 0x1F,
+ BIF_ERR_SLAVE_BUSY = 0x20,
+ BIF_ERR_FATAL = 0x7F,
+};
+
+/**
+ * struct bif_protocol_function - constant data present in protocol function
+ * @l2_entry: Pointer to protocol function L2 DDB data struct
+ * @protocol_pointer: BIF slave address where protocol registers begin
+ * @device_id_pointer: BIF slave address where device ID begins
+ * @device_id: The 8-byte unique device ID in MSB to LSB order
+ */
+struct bif_protocol_function {
+ struct bif_ddb_l2_data *l2_entry;
+ u16 protocol_pointer;
+ u16 device_id_pointer;
+ u8 device_id[BIF_DEVICE_ID_BYTE_LENGTH]; /* Unique ID */
+};
+
+#define PROTOCOL_FUNC_DEV_ADR_ADDR(protocol_pointer) ((protocol_pointer) + 0)
+#define PROTOCOL_FUNC_ERR_CODE_ADDR(protocol_pointer) ((protocol_pointer) + 2)
+#define PROTOCOL_FUNC_ERR_CNT_ADDR(protocol_pointer) ((protocol_pointer) + 3)
+#define PROTOCOL_FUNC_WORD_CNT_ADDR(protocol_pointer) ((protocol_pointer) + 4)
+
+/**
+ * struct bif_slave_control_function - constant data present in slave control
+ * function as well internal software state parameters
+ * @l2_entry: Pointer to slave control function L2 DDB data struct
+ * @slave_ctrl_pointer: BIF slave address where slave control registers begin
+ * @task_count: Number of tasks supported by the slave
+ * @irq_notifier_list: List of notifiers for consumers drivers that wish to be
+ * notified when any given interrupt triggers. This list
+ * is dynamically allocated with length task_count.
+ */
+struct bif_slave_control_function {
+ struct bif_ddb_l2_data *l2_entry;
+ u16 slave_ctrl_pointer;
+ unsigned int task_count;
+ struct blocking_notifier_head *irq_notifier_list;
+};
+
+#define SLAVE_CTRL_TASKS_PER_SET 8
+
+/**
+ * bif_slave_control_task_is_valid() - returns true if the specified task
+ * is supported by the slave or false if it isn't
+ * @func: Pointer to slave's slave control function structure
+ * @task: Slave task number to check
+ */
+static inline bool
+bif_slave_control_task_is_valid(struct bif_slave_control_function *func,
+ unsigned int task)
+{
+ return func ? task < func->task_count : false;
+}
+
+#define SLAVE_CTRL_FUNC_IRQ_EN_ADDR(slave_ctrl_pointer, task) \
+ ((slave_ctrl_pointer) + 4 * ((task) / SLAVE_CTRL_TASKS_PER_SET) + 0)
+
+#define SLAVE_CTRL_FUNC_IRQ_STATUS_ADDR(slave_ctrl_pointer, task) \
+ ((slave_ctrl_pointer) + 4 * ((task) / SLAVE_CTRL_TASKS_PER_SET) + 1)
+#define SLAVE_CTRL_FUNC_IRQ_CLEAR_ADDR(slave_ctrl_pointer, task) \
+ SLAVE_CTRL_FUNC_IRQ_STATUS_ADDR(slave_ctrl_pointer, task)
+
+#define SLAVE_CTRL_FUNC_TASK_TRIGGER_ADDR(slave_ctrl_pointer, task) \
+ ((slave_ctrl_pointer) + 4 * ((task) / SLAVE_CTRL_TASKS_PER_SET) + 2)
+#define SLAVE_CTRL_FUNC_TASK_BUSY_ADDR(slave_ctrl_pointer, task) \
+ SLAVE_CTRL_FUNC_TASK_TRIGGER_ADDR(slave_ctrl_pointer, task)
+
+#define SLAVE_CTRL_FUNC_TASK_AUTO_TRIGGER_ADDR(slave_ctrl_pointer, task) \
+ ((slave_ctrl_pointer) + 4 * ((task) / SLAVE_CTRL_TASKS_PER_SET) + 3)
+
+/**
+ * struct bif_temperature_function - constant data present in temperature
+ * sensor function
+ * @temperatuer_pointer: BIF slave address where temperature sensor
+ * control registers begin
+ * @slave_control_channel: Slave control channel associated with the
+ * temperature sensor function. This channel is
+ * also the task number.
+ * @accuracy_pointer: BIF slave address where temperature accuracy
+ * registers begin
+ */
+struct bif_temperature_function {
+ u16 temperature_pointer;
+ u8 slave_control_channel;
+ u16 accuracy_pointer;
+};
+
+/**
+ * enum bif_mipi_object_type - MIPI defined BIF object types
+ * %BIF_OBJ_END_OF_LIST: Indicates that the end of the object list in
+ * NVM has been reached
+ * %BIF_OBJ_SEC_SLAVE: Specifies the UIDs of secondary slaves found
+ * inside of the battery pack
+ * %BIF_OBJ_BATT_PARAM: Specifies some variety of battery parameter.
+ * There is no MIPI defined format for this object
+ * type so parsing is manufacturer specific.
+ */
+enum bif_mipi_object_type {
+ BIF_OBJ_END_OF_LIST = 0x00,
+ BIF_OBJ_SEC_SLAVE = 0x01,
+ BIF_OBJ_BATT_PARAM = 0x02,
+};
+
+/**
+ * struct bif_object - contains all header and data information for a slave
+ * data object
+ * @type: Object type
+ * @version: Object version
+ * @manufacturer_id: Manufacturer ID number allocated by MIPI
+ * @length: Length of the entire object including header and CRC
+ * @data: Raw byte data found in the object
+ * @crc: CRC of the object calculated using CRC-CCITT
+ * @list: Linked-list connection parameter
+ * @addr: BIF slave address correspond to the start of the object
+ *
+ * manufacturer_id == 0x0000 if MIPI type and version.
+ */
+struct bif_object {
+ u8 type;
+ u8 version;
+ u16 manufacturer_id;
+ u16 length;
+ u8 *data;
+ u16 crc;
+ struct list_head list;
+ u16 addr;
+};
+
+/**
+ * struct bif_nvm_function - constant data present in non-volatile memory
+ * function as well internal software state
+ * parameters
+ * @nvm_pointer: BIF slave address where NVM registers begin
+ * @slave_control_channel: Slave control channel associated with the
+ * NVM function. This channel is also the task
+ * number.
+ * @write_buffer_size: Size in bytes of the NVM write buffer. 0x00
+ * is used to denote a 256 byte buffer.
+ * @nvm_base_address: BIF slave address where NVM begins
+ * @nvm_size: NVM size in bytes
+ * @object_count: Number of BIF objects read from NVM
+ * @object_list: List of BIF objects read from NVM
+ */
+struct bif_nvm_function {
+ u16 nvm_pointer;
+ u8 slave_control_channel;
+ u8 write_buffer_size;
+ u16 nvm_base_address;
+ u16 nvm_size;
+ int object_count;
+ struct list_head object_list;
+};
+
+/**
+ * struct bif_ctrl - Opaque handle for a BIF controller to be used in bus
+ * oriented BIF function calls.
+ */
+struct bif_ctrl;
+
+/**
+ * struct bif_slave - Opaque handle for a BIF slave to be used in slave oriented
+ * BIF function calls.
+ */
+struct bif_slave;
+
+/**
+ * enum bif_bus_state - indicates the current or desired state of the BIF bus
+ * %BIF_BUS_STATE_MASTER_DISABLED: BIF host hardware is disabled
+ * %BIF_BUS_STATE_POWER_DOWN: BIF bus is in power down state and
+ * BCL is not being pulled high
+ * %BIF_BUS_STATE_STANDBY: BIF slaves are in standby state in which
+ * less power is drawn
+ * %BIF_BUS_STATE_ACTIVE: BIF slaves are ready for immediate
+ * communications
+ * %BIF_BUS_STATE_INTERRUPT: BIF bus is active, but no communication
+ * is possible. Instead, either one of the
+ * slaves or the master must transition to
+ * active state by pulling BCL low for 1
+ * tau bif period.
+ */
+enum bif_bus_state {
+ BIF_BUS_STATE_MASTER_DISABLED,
+ BIF_BUS_STATE_POWER_DOWN,
+ BIF_BUS_STATE_STANDBY,
+ BIF_BUS_STATE_ACTIVE,
+ BIF_BUS_STATE_INTERRUPT,
+};
+
+/**
+ * enum bif_bus_event - events that the BIF framework may send to BIF consumers
+ * %BIF_BUS_EVENT_BATTERY_INSERTED: Indicates that a battery was just
+ * inserted physically or that the BIF
+ * host controller for the battery just
+ * probed and a battery was already
+ * present.
+ * %BIF_BUS_EVENT_BATTERY_REMOVED: Indicates that a battery was just
+ * removed and thus its slaves are no
+ * longer accessible.
+ */
+enum bif_bus_event {
+ BIF_BUS_EVENT_BATTERY_INSERTED,
+ BIF_BUS_EVENT_BATTERY_REMOVED,
+};
+
+/* Mask values to be ORed together for use in bif_match_criteria.match_mask. */
+#define BIF_MATCH_MANUFACTURER_ID BIT(0)
+#define BIF_MATCH_PRODUCT_ID BIT(1)
+#define BIF_MATCH_FUNCTION_TYPE BIT(2)
+#define BIF_MATCH_FUNCTION_VERSION BIT(3)
+#define BIF_MATCH_IGNORE_PRESENCE BIT(4)
+
+/**
+ * struct bif_match_criteria - specifies the matching criteria that a BIF
+ * consumer uses to find an appropriate BIF slave
+ * @match_mask: Mask value specifying which parameters to match upon.
+ * This value should be some ORed combination of
+ * BIF_MATCH_* specified above.
+ * @manufacturer_id: Manufacturer ID number allocated by MIPI
+ * @product_id: Manufacturer specified product ID number
+ * @function_type: Defines the type of the function. The type may be
+ * either MIPI or manufacturer defined.
+ * @function_version: Defines the version of the function. The version may
+ * be either MIPI or manufacturer defined.
+ * @ignore_presence: If true, then slaves that are currently not present
+ * will be successfully matched against. By default, only
+ * present slaves can be matched.
+ */
+struct bif_match_criteria {
+ u32 match_mask;
+ u16 manufacturer_id;
+ u16 product_id;
+ u8 function_type;
+ u8 function_version;
+ bool ignore_presence;
+};
+
+/**
+ * bif_battery_rid_ranges - MIPI-BIF defined Rid battery pack resistance ranges
+ * %BIF_BATT_RID_SPECIAL1_MIN: Minimum Rid for special case 1
+ * %BIF_BATT_RID_SPECIAL1_MAX: Maximum Rid for special case 1
+ * %BIF_BATT_RID_SPECIAL2_MIN: Minimum Rid for special case 2
+ * %BIF_BATT_RID_SPECIAL2_MAX: Maximum Rid for special case 2
+ * %BIF_BATT_RID_SPECIAL3_MIN: Minimum Rid for special case 3
+ * %BIF_BATT_RID_SPECIAL3_MAX: Maximum Rid for special case 3
+ * %BIF_BATT_RID_LOW_COST_MIN: Minimum Rid for a low cost battery pack
+ * %BIF_BATT_RID_LOW_COST_MAX: Maximum Rid for a low cost battery pack
+ * %BIF_BATT_RID_SMART_MIN: Minimum Rid for a smart battery pack
+ * %BIF_BATT_RID_SMART_MAX: Maximum Rid for a smart battery pack
+ */
+enum bif_battery_rid_ranges {
+ BIF_BATT_RID_SPECIAL1_MIN = 0,
+ BIF_BATT_RID_SPECIAL1_MAX = 1,
+ BIF_BATT_RID_SPECIAL2_MIN = 7350,
+ BIF_BATT_RID_SPECIAL2_MAX = 7650,
+ BIF_BATT_RID_SPECIAL3_MIN = 12740,
+ BIF_BATT_RID_SPECIAL3_MAX = 13260,
+ BIF_BATT_RID_LOW_COST_MIN = 19600,
+ BIF_BATT_RID_LOW_COST_MAX = 140000,
+ BIF_BATT_RID_SMART_MIN = 240000,
+ BIF_BATT_RID_SMART_MAX = 450000,
+};
+
+#ifdef CONFIG_BIF
+
+int bif_request_irq(struct bif_slave *slave, unsigned int task,
+ struct notifier_block *nb);
+int bif_free_irq(struct bif_slave *slave, unsigned int task,
+ struct notifier_block *nb);
+
+int bif_trigger_task(struct bif_slave *slave, unsigned int task);
+int bif_task_is_busy(struct bif_slave *slave, unsigned int task);
+
+int bif_ctrl_count(void);
+struct bif_ctrl *bif_ctrl_get_by_id(unsigned int id);
+struct bif_ctrl *bif_ctrl_get(struct device *consumer_dev);
+void bif_ctrl_put(struct bif_ctrl *ctrl);
+
+int bif_ctrl_signal_battery_changed(struct bif_ctrl *ctrl);
+
+int bif_slave_match_count(const struct bif_ctrl *ctrl,
+ const struct bif_match_criteria *match_criteria);
+
+struct bif_slave *bif_slave_match_get(const struct bif_ctrl *ctrl,
+ unsigned int id, const struct bif_match_criteria *match_criteria);
+
+void bif_slave_put(struct bif_slave *slave);
+
+int bif_ctrl_notifier_register(struct bif_ctrl *ctrl,
+ struct notifier_block *nb);
+
+int bif_ctrl_notifier_unregister(struct bif_ctrl *ctrl,
+ struct notifier_block *nb);
+
+struct bif_ctrl *bif_get_ctrl_handle(struct bif_slave *slave);
+
+int bif_slave_find_function(struct bif_slave *slave, u8 function, u8 *version,
+ u16 *function_pointer);
+
+int bif_slave_read(struct bif_slave *slave, u16 addr, u8 *buf, int len);
+int bif_slave_write(struct bif_slave *slave, u16 addr, u8 *buf, int len);
+
+int bif_slave_is_present(struct bif_slave *slave);
+
+int bif_slave_is_selected(struct bif_slave *slave);
+int bif_slave_select(struct bif_slave *slave);
+
+int bif_ctrl_raw_transaction(struct bif_ctrl *ctrl, int transaction, u8 data);
+int bif_ctrl_raw_transaction_read(struct bif_ctrl *ctrl, int transaction,
+ u8 data, int *response);
+int bif_ctrl_raw_transaction_query(struct bif_ctrl *ctrl, int transaction,
+ u8 data, bool *query_response);
+
+void bif_ctrl_bus_lock(struct bif_ctrl *ctrl);
+void bif_ctrl_bus_unlock(struct bif_ctrl *ctrl);
+
+u16 bif_crc_ccitt(const u8 *buffer, unsigned int len);
+
+int bif_ctrl_measure_rid(struct bif_ctrl *ctrl);
+int bif_ctrl_get_bus_period(struct bif_ctrl *ctrl);
+int bif_ctrl_set_bus_period(struct bif_ctrl *ctrl, int period_ns);
+int bif_ctrl_get_bus_state(struct bif_ctrl *ctrl);
+int bif_ctrl_set_bus_state(struct bif_ctrl *ctrl, enum bif_bus_state state);
+
+#else
+
+static inline int bif_request_irq(struct bif_slave *slave, unsigned int task,
+ struct notifier_block *nb) { return -EPERM; }
+static inline int bif_free_irq(struct bif_slave *slave, unsigned int task,
+ struct notifier_block *nb) { return -EPERM; }
+
+static inline int bif_trigger_task(struct bif_slave *slave, unsigned int task)
+{ return -EPERM; }
+static inline int bif_task_is_busy(struct bif_slave *slave, unsigned int task)
+{ return -EPERM; }
+
+static inline int bif_ctrl_count(void) { return -EPERM; }
+static inline struct bif_ctrl *bif_ctrl_get_by_id(unsigned int id)
+{ return ERR_PTR(-EPERM); }
+struct bif_ctrl *bif_ctrl_get(struct device *consumer_dev)
+{ return ERR_PTR(-EPERM); }
+static inline void bif_ctrl_put(struct bif_ctrl *ctrl) { return; }
+
+int bif_ctrl_signal_battery_changed(struct bif_ctrl *ctrl) { return -EPERM; }
+
+static inline int bif_slave_match_count(const struct bif_ctrl *ctrl,
+ const struct bif_match_criteria *match_criteria)
+{ return -EPERM; }
+
+static inline struct bif_slave *bif_slave_match_get(const struct bif_ctrl *ctrl,
+ unsigned int id, const struct bif_match_criteria *match_criteria)
+{ return ERR_PTR(-EPERM); }
+
+static inline void bif_slave_put(struct bif_slave *slave) { return; }
+
+static inline int bif_ctrl_notifier_register(struct bif_ctrl *ctrl,
+ struct notifier_block *nb)
+{ return -EPERM; }
+
+static inline int bif_ctrl_notifier_unregister(struct bif_ctrl *ctrl,
+ struct notifier_block *nb)
+{ return -EPERM; }
+
+static inline struct bif_ctrl *bif_get_ctrl_handle(struct bif_slave *slave)
+{ return ERR_PTR(-EPERM); }
+
+static inline int bif_slave_find_function(struct bif_slave *slave, u8 function,
+ u8 *version, u16 *function_pointer)
+{ return -EPERM; }
+
+static inline int bif_slave_read(struct bif_slave *slave, u16 addr, u8 *buf,
+ int len)
+{ return -EPERM; }
+static inline int bif_slave_write(struct bif_slave *slave, u16 addr, u8 *buf,
+ int len)
+{ return -EPERM; }
+
+int bif_slave_is_present(struct bif_slave *slave) { return -EPERM; }
+
+int bif_slave_is_selected(struct bif_slave *slave) { return -EPERM; }
+int bif_slave_select(struct bif_slave *slave) { return -EPERM; }
+
+int bif_ctrl_raw_transaction(struct bif_ctrl *ctrl, int transaction, u8 data)
+{ return -EPERM; }
+int bif_ctrl_raw_transaction_read(struct bif_ctrl *ctrl, int transaction,
+ u8 data, int *response)
+{ return -EPERM; }
+int bif_ctrl_raw_transaction_query(struct bif_ctrl *ctrl, int transaction,
+ u8 data, bool *query_response)
+{ return -EPERM; }
+
+static inline void bif_ctrl_bus_lock(struct bif_ctrl *ctrl)
+{ return -EPERM; }
+static inline void bif_ctrl_bus_unlock(struct bif_ctrl *ctrl)
+{ return -EPERM; }
+
+static inline u16 bif_crc_ccitt(const u8 *buffer, unsigned int len)
+{ return 0; }
+
+static inline int bif_ctrl_measure_rid(struct bif_ctrl *ctrl) { return -EPERM; }
+int bif_ctrl_get_bus_period(struct bif_ctrl *ctrl) { return -EPERM; }
+int bif_ctrl_set_bus_period(struct bif_ctrl *ctrl, int period_ns)
+{ return -EPERM; }
+int bif_ctrl_get_bus_state(struct bif_ctrl *ctrl) { return -EPERM; }
+int bif_ctrl_set_bus_state(struct bif_ctrl *ctrl, enum bif_bus_state state)
+{ return -EPERM; }
+
+#endif
+
+#endif
diff --git a/include/linux/bif/driver.h b/include/linux/bif/driver.h
new file mode 100644
index 0000000..184d46f
--- /dev/null
+++ b/include/linux/bif/driver.h
@@ -0,0 +1,161 @@
+/* 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.
+ */
+
+#ifndef _LINUX_BIF_DRIVER_H_
+#define _LINUX_BIF_DRIVER_H_
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/types.h>
+#include <linux/bif/consumer.h>
+
+/**
+ * struct bif_ctrl_dev - opaque handle used to identify a given BIF controller
+ * device
+ */
+struct bif_ctrl_dev;
+
+/**
+ * struct bif_ctrl_ops - BIF operations which may be implemented by BIF
+ * controller drivers
+ * @bus_transaction: Perform the specified BIF transaction which does
+ * not result in any slave response.
+ * @bus_transaction_query: Perform the specified BIF transaction which
+ * expects a BQ response in the case of slave
+ * positive acknowledgement.
+ * @bus_transaction_read: Perform the specified BIF transaction which
+ * expects an RD or TACK response from the selected
+ * slave.
+ * @read_slave_registers: Perform all BIF transactions necessary to read
+ * the specified set of contiguous registers from
+ * the previously selected slave. This operation
+ * is used to optimize the common case of slave
+ * register reads since the a BIF controller driver
+ * can take advantage of BIF burst reads while the
+ * BIF core driver cannot due to the inherient
+ * tight timing requirements.
+ * @write_slave_registers: Perform all BIF transactions necessary to write
+ * the specified set of contiguous registers to
+ * the previously selected slave. This operation
+ * is used to optimize the common case of slave
+ * register writes since the a BIF controller
+ * driver can remove redundant steps when
+ * performing several WD commands in a row.
+ * @get_bus_period: Return the tau_bif BIF bus clock period in
+ * nanoseconds.
+ * @set_bus_period: Set the tau_bif BIF bus clock period in
+ * nanoseconds. If the exact period is not
+ * supported by the BIF controller hardware, then
+ * the next larger supported period should be used.
+ * @get_battery_presence: Return the current state of the battery pack.
+ * If a battery pack is present, then return >= 1.
+ * If a battery pack is not present, then return 0.
+ * If an error occurs during presence detection,
+ * then return errno.
+ * @get_battery_rid: Return the measured value of the Rid battery
+ * pack pull-down resistor in ohms.
+ * @get_bus_state: Return the current bus state as defined by one
+ * of the enum bif_bus_state values.
+ * @set_bus_state: Set the BIF bus state to the specified enum
+ * bif_bus_state value.
+ *
+ * The following operations must be defined by every BIF controller driver in
+ * order to ensure baseline functionality:
+ * bus_transaction, bus_transaction_query, get_bus_state, and set_bus_state.
+ *
+ * The BIF core driver is unaware of BIF transaction timing constraints. A
+ * given BIF controller driver must ensure that all timing constraints in the
+ * MIPI-BIF specification are met as transactions are carried out.
+ *
+ * Conversion between 11-bit and 17-bit BIF words (i.e. the insertion of BCF_n,
+ * parity bits, and the inversion bit) must be handled inside of the BIF
+ * controller driver (either in software or hardware). This guarantees maximum
+ * performance if hardware support is available.
+ *
+ * The bus_transaction_read operation must return -ETIMEDOUT in the case of no
+ * RD or TACK word received. This allows the transaction query, TQ, command
+ * to be used for slave selection verification.
+ *
+ * It is acceptable for the BIF bus state to be changed autonomously by a BIF
+ * controller driver in response to low level bus actions without a call to
+ * set_bus_state. One example is the case of receiving a slave interrupt
+ * while in interrupt state as this intrinsically causes the bus to enter the
+ * active communication state.
+ */
+struct bif_ctrl_ops {
+ int (*bus_transaction) (struct bif_ctrl_dev *bdev, int transaction,
+ u8 data);
+ int (*bus_transaction_query) (struct bif_ctrl_dev *bdev,
+ int transaction, u8 data,
+ bool *query_response);
+ int (*bus_transaction_read) (struct bif_ctrl_dev *bdev,
+ int transaction, u8 data,
+ int *response);
+ int (*read_slave_registers) (struct bif_ctrl_dev *bdev, u16 addr,
+ u8 *data, int len);
+ int (*write_slave_registers) (struct bif_ctrl_dev *bdev, u16 addr,
+ const u8 *data, int len);
+ int (*get_bus_period) (struct bif_ctrl_dev *bdev);
+ int (*set_bus_period) (struct bif_ctrl_dev *bdev, int period_ns);
+ int (*get_battery_presence) (struct bif_ctrl_dev *bdev);
+ int (*get_battery_rid) (struct bif_ctrl_dev *bdev);
+ int (*get_bus_state) (struct bif_ctrl_dev *bdev);
+ int (*set_bus_state) (struct bif_ctrl_dev *bdev, int state);
+};
+
+/**
+ * struct bif_ctrl_desc - BIF bus controller descriptor
+ * @name: Name used to identify the BIF controller
+ * @ops: BIF operations supported by the BIF controller
+ * @bus_clock_min_ns: Minimum tau_bif BIF bus clock period supported by the
+ * BIF controller
+ * @bus_clock_max_ns: Maximum tau_bif BIF bus clock period supported by the
+ * BIF controller
+ *
+ * Each BIF controller registered with the BIF core is described with a
+ * structure of this type.
+ */
+struct bif_ctrl_desc {
+ const char *name;
+ struct bif_ctrl_ops *ops;
+ int bus_clock_min_ns;
+ int bus_clock_max_ns;
+};
+
+#ifdef CONFIG_BIF
+
+struct bif_ctrl_dev *bif_ctrl_register(struct bif_ctrl_desc *bif_desc,
+ struct device *dev, void *driver_data, struct device_node *of_node);
+
+void bif_ctrl_unregister(struct bif_ctrl_dev *bdev);
+
+void *bdev_get_drvdata(struct bif_ctrl_dev *bdev);
+
+int bif_ctrl_notify_battery_changed(struct bif_ctrl_dev *bdev);
+int bif_ctrl_notify_slave_irq(struct bif_ctrl_dev *bdev);
+
+#else
+
+static inline struct bif_ctrl_dev *bif_ctrl_register(
+ struct bif_ctrl_desc *bif_desc, struct device *dev, void *driver_data,
+ struct device_node *of_node)
+{ return ERR_PTR(-EINVAL); }
+
+static inline void bif_ctrl_unregister(struct bif_ctrl_dev *bdev) { }
+
+static inline void *bdev_get_drvdata(struct bif_ctrl_dev *bdev) { return NULL; }
+
+int bif_ctrl_notify_slave_irq(struct bif_ctrl_dev *bdev) { return -EINVAL; }
+
+#endif
+
+#endif