M7350/kernel/drivers/bif/bif-core.c
2024-09-09 08:57:42 +00:00

3842 lines
100 KiB
C

/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#define pr_fmt(fmt) "%s: " fmt, __func__
#include <linux/bitrev.h>
#include <linux/crc-ccitt.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/workqueue.h>
#include <linux/bif/consumer.h>
#include <linux/bif/driver.h>
/**
* struct bif_ctrl_dev - holds controller device specific information
* @list: Doubly-linked list parameter linking to other
* BIF controllers registered in the system
* @desc: Description structure for this BIF controller
* @mutex: Mutex lock that is used to ensure mutual
* exclusion between transactions performed on the
* BIF bus for this controller
* @ctrl_dev: Device pointer to the BIF controller device
* @driver_data: Private data used by the BIF controller
* @selected_sdev: Slave device that is currently selected on
* the BIF bus of this controller
* @bus_change_notifier: Head of a notifier list containing notifier
* blocks that are notified when the battery
* presence changes
* @enter_irq_mode_work: Work task that is scheduled after a transaction
* completes when there are consumers that are
* actively monitoring BIF slave interrupts
* @irq_count: This is a count of the total number of BIF slave
* interrupts that are currently being monitored
* for the BIF slaves connected to this BIF
* controller
* @irq_mode_delay_jiffies: Number of jiffies to wait before scheduling the
* enter IRQ mode task. Using a larger value
* helps to improve the performance of BIF
* consumers that perform many BIF transactions.
* Using a smaller value reduces the latency of
* BIF slave interrupts.
* @battery_present: Cached value of the battery presence. This is
* used to filter out spurious presence update
* calls when the battery presence state has not
* changed.
*/
struct bif_ctrl_dev {
struct list_head list;
struct bif_ctrl_desc *desc;
struct mutex mutex;
struct device *ctrl_dev;
void *driver_data;
struct bif_slave_dev *selected_sdev;
struct blocking_notifier_head bus_change_notifier;
struct delayed_work enter_irq_mode_work;
int irq_count;
int irq_mode_delay_jiffies;
bool battery_present;
};
/**
* struct bif_ctrl - handle used by BIF consumers for bus oriented BIF
* operations
* @bdev: Pointer to BIF controller device
* @exclusive_lock: Flag which indicates that the BIF consumer responsible
* for this handle has locked the BIF bus of this
* controller. BIF transactions from other consumers are
* blocked until the bus is unlocked.
*/
struct bif_ctrl {
struct bif_ctrl_dev *bdev;
bool exclusive_lock;
};
/**
* struct bif_slave_dev - holds BIF slave device information
* @list: Doubly-linked list parameter linking to other
* BIF slaves that have been enumerated
* @bdev: Pointer to the BIF controller device that this
* slave is physically connected to
* @slave_addr: 8-bit BIF DEV_ADR assigned to this slave
* @unique_id: 80-bit BIF unique ID of the slave
* @unique_id_bits_known: Number of bits of the UID that are currently
* known. This number starts is incremented during
* a UID search and must end at 80 if the slave
* responds to the search properly.
* @present: Boolean value showing if this slave is
* physically present in the system at a given
* point in time. The value is set to false if the
* battery pack containing the slave is
* disconnected.
* @l1_data: BIF DDB L1 data of the slave as read from the
* slave's memory
* @function_directory: Pointer to the BIF DDB L2 function directory
* list as read from the slave's memory
* @protocol_function: Pointer to constant protocol function data as
* well as software state information if the slave
* has a protocol function
* @slave_ctrl_function: Pointer to constant slave control function data
* as well as software state information if the
* slave has a slave control function
* @nvm_function: Pointer to constant non-volatile memory function
* data as well as software state information if
* the slave has a non-volatile memory function
*
* bif_slave_dev objects are stored indefinitely after enumeration in order to
* speed up battery reinsertion. Only a UID check is needed after inserting a
* battery assuming it has been enumerated before.
*
* unique_id bytes are stored such that unique_id[0] = MSB and
* unique_id[BIF_UNIQUE_ID_BYTE_LENGTH - 1] = LSB
*/
struct bif_slave_dev {
struct list_head list;
struct bif_ctrl_dev *bdev;
u8 slave_addr;
u8 unique_id[BIF_UNIQUE_ID_BYTE_LENGTH];
int unique_id_bits_known;
bool present;
struct bif_ddb_l1_data l1_data;
struct bif_ddb_l2_data *function_directory;
struct bif_protocol_function *protocol_function;
struct bif_slave_control_function *slave_ctrl_function;
struct bif_nvm_function *nvm_function;
};
/**
* struct bif_slave - handle used by BIF consumers for slave oriented BIF
* operations
* @ctrl: Consumer BIF controller handle data
* @sdev: Pointer to BIF slave device
*/
struct bif_slave {
struct bif_ctrl ctrl;
struct bif_slave_dev *sdev;
};
/* Number of times to retry a full BIF transaction before returning an error. */
#define BIF_TRANSACTION_RETRY_COUNT 5
static DEFINE_MUTEX(bif_ctrl_list_mutex);
static LIST_HEAD(bif_ctrl_list);
static DEFINE_MUTEX(bif_sdev_list_mutex);
static LIST_HEAD(bif_sdev_list);
static u8 next_dev_addr = 0x02;
#define DEBUG_PRINT_BUFFER_SIZE 256
static void fill_string(char *str, size_t str_len, u8 *buf, int buf_len)
{
int pos = 0;
int i;
for (i = 0; i < buf_len; i++) {
pos += scnprintf(str + pos, str_len - pos, "0x%02X", buf[i]);
if (i < buf_len - 1)
pos += scnprintf(str + pos, str_len - pos, ", ");
}
}
static void bif_print_slave_data(struct bif_slave_dev *sdev)
{
char str[DEBUG_PRINT_BUFFER_SIZE];
u8 *uid;
int i, j;
struct bif_object *object;
if (sdev->unique_id_bits_known != BIF_UNIQUE_ID_BIT_LENGTH)
return;
uid = sdev->unique_id;
pr_debug("BIF slave: 0x%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X\n",
uid[0], uid[1], uid[2], uid[3], uid[4], uid[5], uid[6],
uid[7], uid[8], uid[9]);
pr_debug(" present=%d, dev_adr=0x%02X\n", sdev->present,
sdev->slave_addr);
pr_debug(" revision=0x%02X, level=0x%02X, device class=0x%04X\n",
sdev->l1_data.revision, sdev->l1_data.level,
sdev->l1_data.device_class);
pr_debug(" manufacturer ID=0x%04X, product ID=0x%04X\n",
sdev->l1_data.manufacturer_id, sdev->l1_data.product_id);
pr_debug(" function directory length=%d\n", sdev->l1_data.length);
for (i = 0; i < sdev->l1_data.length / 4; i++) {
pr_debug(" Function %d: type=0x%02X, version=0x%02X, pointer=0x%04X\n",
i, sdev->function_directory[i].function_type,
sdev->function_directory[i].function_version,
sdev->function_directory[i].function_pointer);
}
if (sdev->nvm_function) {
pr_debug(" NVM function: pointer=0x%04X, task=%d, wr_buf_size=%d, nvm_base=0x%04X, nvm_size=%d, nvm_lock_offset=%d\n",
sdev->nvm_function->nvm_pointer,
sdev->nvm_function->slave_control_channel,
(sdev->nvm_function->write_buffer_size
? sdev->nvm_function->write_buffer_size : 0),
sdev->nvm_function->nvm_base_address,
sdev->nvm_function->nvm_size,
sdev->nvm_function->nvm_lock_offset);
if (sdev->nvm_function->object_count)
pr_debug(" NVM objects:\n");
i = 0;
list_for_each_entry(object, &sdev->nvm_function->object_list,
list) {
pr_debug(" Object %d - addr=0x%04X, data len=%d, type=0x%02X, version=0x%02X, manufacturer ID=0x%04X, crc=0x%04X\n",
i, object->addr, object->length - 8,
object->type, object->version,
object->manufacturer_id, object->crc);
for (j = 0; j < DIV_ROUND_UP(object->length - 8, 16);
j++) {
fill_string(str, DEBUG_PRINT_BUFFER_SIZE,
object->data + j * 16,
min(16, object->length - 8 - (j * 16)));
pr_debug(" data(0x%04X): %s\n", j * 16,
str);
}
i++;
}
}
}
static void bif_print_slaves(void)
{
struct bif_slave_dev *sdev;
mutex_lock(&bif_sdev_list_mutex);
list_for_each_entry(sdev, &bif_sdev_list, list) {
/* Skip slaves without fully known UIDs. */
if (sdev->unique_id_bits_known != BIF_UNIQUE_ID_BIT_LENGTH)
continue;
bif_print_slave_data(sdev);
}
mutex_unlock(&bif_sdev_list_mutex);
}
static struct bif_slave_dev *bif_add_slave(struct bif_ctrl_dev *bdev)
{
struct bif_slave_dev *sdev;
sdev = kzalloc(sizeof(struct bif_slave_dev), GFP_KERNEL);
if (sdev == NULL) {
pr_err("Memory allocation failed for bif_slave_dev\n");
return ERR_PTR(-ENOMEM);
}
sdev->bdev = bdev;
INIT_LIST_HEAD(&sdev->list);
list_add_tail(&sdev->list, &bif_sdev_list);
return sdev;
}
static void bif_remove_slave(struct bif_slave_dev *sdev)
{
list_del(&sdev->list);
if (sdev->bdev->selected_sdev == sdev)
sdev->bdev->selected_sdev = NULL;
if (sdev->slave_ctrl_function)
kfree(sdev->slave_ctrl_function->irq_notifier_list);
kfree(sdev->slave_ctrl_function);
kfree(sdev->protocol_function);
kfree(sdev->function_directory);
kfree(sdev);
}
/* This function assumes that the uid array is all 0 to start with. */
static void set_uid_bit(u8 uid[BIF_UNIQUE_ID_BYTE_LENGTH], unsigned int bit,
unsigned int value)
{
u8 mask;
if (bit >= BIF_UNIQUE_ID_BIT_LENGTH)
return;
mask = 1 << (7 - (bit % 8));
uid[bit / 8] &= ~mask;
uid[bit / 8] |= value << (7 - (bit % 8));
}
static unsigned int get_uid_bit(u8 uid[BIF_UNIQUE_ID_BYTE_LENGTH],
unsigned int bit)
{
if (bit >= BIF_UNIQUE_ID_BIT_LENGTH)
return 0;
return (uid[bit / 8] & (1 << (7 - (bit % 8)))) ? 1 : 0;
}
static void bif_enter_irq_mode_work(struct work_struct *work)
{
struct delayed_work *dwork = to_delayed_work(work);
struct bif_ctrl_dev *bdev
= container_of(dwork, struct bif_ctrl_dev, enter_irq_mode_work);
int rc, i;
mutex_lock(&bdev->mutex);
for (i = 0; i < BIF_TRANSACTION_RETRY_COUNT; i++) {
rc = bdev->desc->ops->set_bus_state(bdev,
BIF_BUS_STATE_INTERRUPT);
if (rc == 0)
break;
}
mutex_unlock(&bdev->mutex);
/* Reschedule the task if the transaction failed. */
if (rc) {
pr_err("Could not set BIF bus to interrupt mode, rc=%d\n", rc);
schedule_delayed_work(&bdev->enter_irq_mode_work,
bdev->irq_mode_delay_jiffies);
}
}
static void bif_cancel_irq_mode_work(struct bif_ctrl_dev *bdev)
{
cancel_delayed_work(&bdev->enter_irq_mode_work);
}
static void bif_schedule_irq_mode_work(struct bif_ctrl_dev *bdev)
{
if (bdev->irq_count > 0 &&
bdev->desc->ops->get_bus_state(bdev) != BIF_BUS_STATE_INTERRUPT)
schedule_delayed_work(&bdev->enter_irq_mode_work,
bdev->irq_mode_delay_jiffies);
}
static int _bif_select_slave_no_retry(struct bif_slave_dev *sdev)
{
struct bif_ctrl_dev *bdev = sdev->bdev;
int rc = 0;
int i;
/* Check if the slave is already selected. */
if (sdev->bdev->selected_sdev == sdev)
return 0;
if (sdev->slave_addr) {
/* Select using DEV_ADR. */
rc = bdev->desc->ops->bus_transaction(bdev, BIF_TRANS_SDA,
sdev->slave_addr);
if (!rc)
sdev->bdev->selected_sdev = sdev;
} else if (sdev->unique_id_bits_known == BIF_UNIQUE_ID_BIT_LENGTH) {
/* Select using full UID. */
for (i = 0; i < BIF_UNIQUE_ID_BYTE_LENGTH - 1; i++) {
rc = bdev->desc->ops->bus_transaction(bdev,
BIF_TRANS_EDA, sdev->unique_id[i]);
if (rc)
goto out;
}
rc = bdev->desc->ops->bus_transaction(bdev, BIF_TRANS_SDA,
sdev->unique_id[BIF_UNIQUE_ID_BYTE_LENGTH - 1]);
if (rc)
goto out;
} else {
pr_err("Cannot select slave because it has neither UID nor DEV_ADR.\n");
return -EINVAL;
}
sdev->bdev->selected_sdev = sdev;
return 0;
out:
pr_err("bus_transaction failed, rc=%d\n", rc);
return rc;
}
static int bif_select_slave(struct bif_slave_dev *sdev)
{
int rc = -EPERM;
int i;
for (i = 0; i < BIF_TRANSACTION_RETRY_COUNT; i++) {
rc = _bif_select_slave_no_retry(sdev);
if (rc == 0)
break;
/* Force slave reselection. */
sdev->bdev->selected_sdev = NULL;
}
return rc;
}
/*
* Returns 1 if slave is selected, 0 if slave is not selected, or errno if
* error.
*/
static int bif_is_slave_selected(struct bif_ctrl_dev *bdev)
{
int rc = -EPERM;
int tack, i;
for (i = 0; i < BIF_TRANSACTION_RETRY_COUNT; i++) {
/* Attempt a transaction query. */
rc = bdev->desc->ops->bus_transaction_read(bdev, BIF_TRANS_BC,
BIF_CMD_TQ, &tack);
if (rc == 0 || rc == -ETIMEDOUT)
break;
}
if (rc == 0)
rc = 1;
else if (rc == -ETIMEDOUT)
rc = 0;
else
pr_err("BIF bus_transaction_read failed, rc=%d\n", rc);
return rc;
}
/* Read from a specified number of consecutive registers. */
static int _bif_slave_read_no_retry(struct bif_slave_dev *sdev, u16 addr,
u8 *buf, int len)
{
struct bif_ctrl_dev *bdev = sdev->bdev;
int rc = 0;
int i, response;
rc = bif_select_slave(sdev);
if (rc)
return rc;
if (bdev->desc->ops->read_slave_registers) {
/*
* Use low level slave register read implementation in order to
* receive the benefits of BIF burst reads.
*/
rc = bdev->desc->ops->read_slave_registers(bdev, addr, buf,
len);
if (rc)
pr_debug("read_slave_registers failed, rc=%d\n", rc);
else
return rc;
/*
* Fall back on individual transactions if high level register
* read failed.
*/
}
for (i = 0; i < len; i++) {
rc = bdev->desc->ops->bus_transaction(bdev, BIF_TRANS_ERA,
addr >> 8);
if (rc) {
pr_err("bus_transaction failed, rc=%d\n", rc);
return rc;
}
rc = bdev->desc->ops->bus_transaction_read(bdev, BIF_TRANS_RRA,
addr & 0xFF, &response);
if (rc) {
pr_err("bus_transaction_read failed, rc=%d\n", rc);
return rc;
}
if (!(response & BIF_SLAVE_RD_ACK)) {
pr_err("BIF register read error=0x%02X\n",
response & BIF_SLAVE_RD_ERR);
return -EIO;
}
buf[i] = response & BIF_SLAVE_RD_DATA;
addr++;
}
return rc;
}
/*
* Read from a specified number of consecutive registers. Retry the transaction
* several times in case of communcation failures.
*/
static int _bif_slave_read(struct bif_slave_dev *sdev, u16 addr, u8 *buf,
int len)
{
int rc = -EPERM;
int i;
for (i = 0; i < BIF_TRANSACTION_RETRY_COUNT; i++) {
rc = _bif_slave_read_no_retry(sdev, addr, buf, len);
if (rc == 0)
break;
/* Force slave reselection. */
sdev->bdev->selected_sdev = NULL;
}
return rc;
}
/* Write to a specified number of consecutive registers. */
static int _bif_slave_write_no_retry(struct bif_slave_dev *sdev, u16 addr,
u8 *buf, int len)
{
struct bif_ctrl_dev *bdev = sdev->bdev;
int rc = 0;
int i;
rc = bif_select_slave(sdev);
if (rc)
return rc;
if (bdev->desc->ops->write_slave_registers) {
/*
* Use low level slave register write implementation in order to
* receive the benefits of BIF burst writes.
*/
rc = bdev->desc->ops->write_slave_registers(bdev, addr, buf,
len);
if (rc)
pr_debug("write_slave_registers failed, rc=%d\n", rc);
else
return rc;
/*
* Fall back on individual transactions if high level register
* write failed.
*/
}
rc = bdev->desc->ops->bus_transaction(bdev, BIF_TRANS_ERA, addr >> 8);
if (rc)
goto out;
rc = bdev->desc->ops->bus_transaction(bdev, BIF_TRANS_WRA, addr & 0xFF);
if (rc)
goto out;
for (i = 0; i < len; i++) {
rc = bdev->desc->ops->bus_transaction(bdev, BIF_TRANS_WD,
buf[i]);
if (rc)
goto out;
}
return 0;
out:
pr_err("bus_transaction failed, rc=%d\n", rc);
return rc;
}
/*
* Write to a specified number of consecutive registers. Retry the transaction
* several times in case of communcation failures.
*/
static int _bif_slave_write(struct bif_slave_dev *sdev, u16 addr, u8 *buf,
int len)
{
int rc = -EPERM;
int i;
for (i = 0; i < BIF_TRANSACTION_RETRY_COUNT; i++) {
rc = _bif_slave_write_no_retry(sdev, addr, buf, len);
if (rc == 0)
break;
/* Force slave reselection. */
sdev->bdev->selected_sdev = NULL;
}
return rc;
}
/* Perform a read-modify-write sequence on a single BIF slave register. */
static int _bif_slave_masked_write(struct bif_slave_dev *sdev, u16 addr, u8 val,
u8 mask)
{
int rc;
u8 reg;
rc = _bif_slave_read(sdev, addr, &reg, 1);
if (rc)
return rc;
reg = (reg & ~mask) | (val & mask);
return _bif_slave_write(sdev, addr, &reg, 1);
}
static int _bif_check_task(struct bif_slave_dev *sdev, unsigned int task)
{
if (IS_ERR_OR_NULL(sdev)) {
pr_err("Invalid slave device handle=%ld\n", PTR_ERR(sdev));
return -EINVAL;
} else if (!sdev->bdev) {
pr_err("BIF controller has been removed\n");
return -ENXIO;
} else if (!sdev->slave_ctrl_function
|| sdev->slave_ctrl_function->task_count == 0) {
pr_err("BIF slave does not support slave control\n");
return -ENODEV;
} else if (task >= sdev->slave_ctrl_function->task_count) {
pr_err("Requested task: %u greater than max: %u for this slave\n",
task, sdev->slave_ctrl_function->task_count);
return -EINVAL;
}
return 0;
}
static int _bif_task_is_busy(struct bif_slave_dev *sdev, unsigned int task)
{
int rc;
u16 addr;
u8 reg = 0;
rc = _bif_check_task(sdev, task);
if (rc) {
pr_err("Invalid slave device or task, rc=%d\n", rc);
return rc;
}
/* Check the task busy state. */
addr = SLAVE_CTRL_FUNC_TASK_BUSY_ADDR(
sdev->slave_ctrl_function->slave_ctrl_pointer, task);
rc = _bif_slave_read(sdev, addr, &reg, 1);
if (rc) {
pr_err("BIF slave register read failed, rc=%d\n", rc);
return rc;
}
return (reg & BIT(task % SLAVE_CTRL_TASKS_PER_SET)) ? 1 : 0;
}
static int _bif_enable_auto_task(struct bif_slave_dev *sdev, unsigned int task)
{
int rc;
u16 addr;
u8 mask;
rc = _bif_check_task(sdev, task);
if (rc) {
pr_err("Invalid slave device or task, rc=%d\n", rc);
return rc;
}
/* Enable the auto task within the slave */
mask = BIT(task % SLAVE_CTRL_TASKS_PER_SET);
addr = SLAVE_CTRL_FUNC_TASK_AUTO_TRIGGER_ADDR(
sdev->slave_ctrl_function->slave_ctrl_pointer, task);
if (task / SLAVE_CTRL_TASKS_PER_SET == 0) {
/* Set global auto task enable. */
mask |= BIT(0);
}
rc = _bif_slave_masked_write(sdev, addr, 0xFF, mask);
if (rc) {
pr_err("BIF slave register masked write failed, rc=%d\n", rc);
return rc;
}
/* Set global auto task enable if task not in set 0. */
if (task / SLAVE_CTRL_TASKS_PER_SET != 0) {
addr = SLAVE_CTRL_FUNC_TASK_AUTO_TRIGGER_ADDR(
sdev->slave_ctrl_function->slave_ctrl_pointer, 0);
rc = _bif_slave_masked_write(sdev, addr, 0xFF, BIT(0));
if (rc) {
pr_err("BIF slave register masked write failed, rc=%d\n",
rc);
return rc;
}
}
return rc;
}
static int _bif_disable_auto_task(struct bif_slave_dev *sdev, unsigned int task)
{
int rc;
u16 addr;
u8 mask;
rc = _bif_check_task(sdev, task);
if (rc) {
pr_err("Invalid slave or task, rc=%d\n", rc);
return rc;
}
/* Disable the auto task within the slave */
mask = BIT(task % SLAVE_CTRL_TASKS_PER_SET);
addr = SLAVE_CTRL_FUNC_TASK_AUTO_TRIGGER_ADDR(
sdev->slave_ctrl_function->slave_ctrl_pointer, task);
rc = _bif_slave_masked_write(sdev, addr, 0x00, mask);
if (rc) {
pr_err("BIF slave register masked write failed, rc=%d\n", rc);
return rc;
}
return rc;
}
/*
* The MIPI-BIF spec does not define a maximum time in which an NVM write must
* complete. The following delay and recheck count therefore represent
* arbitrary but reasonable values.
*/
#define NVM_WRITE_POLL_DELAY_MS 20
#define NVM_WRITE_MAX_POLL_COUNT 50
static int _bif_slave_nvm_raw_write(struct bif_slave_dev *sdev, u16 offset,
u8 *buf, int len)
{
int rc = 0;
int write_len, poll_count, rc2;
u8 write_buf[3];
if (!sdev->nvm_function) {
pr_err("BIF slave has no NVM function\n");
return -ENODEV;
} else if (offset + len > sdev->nvm_function->nvm_size) {
pr_err("write offset + len = %d > NVM size = %d\n",
offset + len, sdev->nvm_function->nvm_size);
return -EINVAL;
} else if (offset < sdev->nvm_function->nvm_lock_offset) {
pr_err("write offset = %d < first writable offset = %d\n",
offset, sdev->nvm_function->nvm_lock_offset);
return -EINVAL;
}
rc = _bif_enable_auto_task(sdev,
sdev->nvm_function->slave_control_channel);
if (rc) {
pr_err("Failed to enable NVM auto task, rc=%d\n", rc);
return rc;
}
while (len > 0) {
write_len = sdev->nvm_function->write_buffer_size;
if (write_len == 0)
write_len = 256;
write_len = min(write_len, len);
write_buf[0] = offset >> 8;
write_buf[1] = offset;
write_buf[2] = (write_len == 256) ? 0 : write_len;
/* Write offset and size registers. */
rc = _bif_slave_write(sdev, sdev->nvm_function->nvm_pointer + 6,
write_buf, 3);
if (rc) {
pr_err("BIF slave write failed, rc=%d\n", rc);
goto done;
}
/* Write to NVM write buffer registers. */
rc = _bif_slave_write(sdev, sdev->nvm_function->nvm_pointer + 9,
buf, write_len);
if (rc) {
pr_err("BIF slave write failed, rc=%d\n", rc);
goto done;
}
/*
* Wait for completion of the NVM write which was auto-triggered
* by the register write of the last byte in the NVM write
* buffer.
*/
poll_count = NVM_WRITE_MAX_POLL_COUNT;
do {
msleep(NVM_WRITE_POLL_DELAY_MS);
rc = _bif_task_is_busy(sdev,
sdev->nvm_function->slave_control_channel);
poll_count--;
} while (rc > 0 && poll_count > 0);
if (rc < 0) {
pr_err("Failed to check task state, rc=%d", rc);
goto done;
} else if (rc > 0) {
pr_err("BIF slave NVM write not completed after %d ms\n",
NVM_WRITE_POLL_DELAY_MS * NVM_WRITE_MAX_POLL_COUNT);
rc = -ETIMEDOUT;
goto done;
}
len -= write_len;
offset += write_len;
buf += write_len;
}
done:
rc2 = _bif_disable_auto_task(sdev,
sdev->nvm_function->slave_control_channel);
if (rc2) {
pr_err("Failed to disable NVM auto task, rc=%d\n", rc2);
return rc2;
}
return rc;
}
/* Takes a mutex if this consumer is not an exclusive bus user. */
static void bif_ctrl_lock(struct bif_ctrl *ctrl)
{
if (!ctrl->exclusive_lock) {
mutex_lock(&ctrl->bdev->mutex);
bif_cancel_irq_mode_work(ctrl->bdev);
}
}
/* Releases a mutex if this consumer is not an exclusive bus user. */
static void bif_ctrl_unlock(struct bif_ctrl *ctrl)
{
if (!ctrl->exclusive_lock) {
bif_schedule_irq_mode_work(ctrl->bdev);
mutex_unlock(&ctrl->bdev->mutex);
}
}
static void bif_slave_ctrl_lock(struct bif_slave *slave)
{
bif_ctrl_lock(&slave->ctrl);
}
static void bif_slave_ctrl_unlock(struct bif_slave *slave)
{
bif_ctrl_unlock(&slave->ctrl);
}
/**
* bif_crc_ccitt() - calculate the CRC-CCITT CRC value of the data specified
* @buffer: Data to calculate the CRC of
* @len: Length of the data buffer in bytes
*
* MIPI-BIF specifies the usage of CRC-CCITT for BIF data objects. This
* function performs the CRC calculation while taking into account the bit
* ordering used by BIF.
*/
u16 bif_crc_ccitt(const u8 *buffer, unsigned int len)
{
u16 crc = 0xFFFF;
while (len--) {
crc = crc_ccitt_byte(crc, bitrev8(*buffer));
buffer++;
}
return bitrev16(crc);
}
EXPORT_SYMBOL(bif_crc_ccitt);
static u16 bif_object_crc_ccitt(const struct bif_object *object)
{
u16 crc = 0xFFFF;
int i;
crc = crc_ccitt_byte(crc, bitrev8(object->type));
crc = crc_ccitt_byte(crc, bitrev8(object->version));
crc = crc_ccitt_byte(crc, bitrev8(object->manufacturer_id >> 8));
crc = crc_ccitt_byte(crc, bitrev8(object->manufacturer_id));
crc = crc_ccitt_byte(crc, bitrev8(object->length >> 8));
crc = crc_ccitt_byte(crc, bitrev8(object->length));
for (i = 0; i < object->length - 8; i++)
crc = crc_ccitt_byte(crc, bitrev8(object->data[i]));
return bitrev16(crc);
}
static int bif_check_task(struct bif_slave *slave, unsigned int task)
{
if (IS_ERR_OR_NULL(slave)) {
pr_err("Invalid slave pointer=%ld\n", PTR_ERR(slave));
return -EINVAL;
}
return _bif_check_task(slave->sdev, task);
}
/**
* bif_request_irq() - request a BIF slave IRQ by slave task number
* @slave: BIF slave handle
* @task: BIF task number of the IRQ inside of the slave. This
* corresponds to the slave control channel specified for a given
* BIF function inside of the slave.
* @nb: Notifier block to call when the IRQ fires
*
* This function registers a notifier block to call when the BIF slave interrupt
* is triggered and also enables the interrupt. The interrupt is enabled inside
* of the BIF slave's slave control function and also the BIF bus is put into
* interrupt mode.
*
* Returns 0 for success or errno if an error occurred.
*/
int bif_request_irq(struct bif_slave *slave, unsigned int task,
struct notifier_block *nb)
{
int rc;
u16 addr;
u8 reg, mask;
rc = bif_check_task(slave, task);
if (rc) {
pr_err("Invalid slave or task, rc=%d\n", rc);
return rc;
}
bif_slave_ctrl_lock(slave);
rc = blocking_notifier_chain_register(
&slave->sdev->slave_ctrl_function->irq_notifier_list[task], nb);
if (rc) {
pr_err("Notifier registration failed, rc=%d\n", rc);
goto done;
}
/* Enable the interrupt within the slave */
mask = BIT(task % SLAVE_CTRL_TASKS_PER_SET);
addr = SLAVE_CTRL_FUNC_IRQ_EN_ADDR(
slave->sdev->slave_ctrl_function->slave_ctrl_pointer, task);
if (task / SLAVE_CTRL_TASKS_PER_SET == 0) {
/* Set global interrupt enable. */
mask |= BIT(0);
}
rc = _bif_slave_read(slave->sdev, addr, &reg, 1);
if (rc) {
pr_err("BIF slave register read failed, rc=%d\n", rc);
goto notifier_unregister;
}
reg |= mask;
rc = _bif_slave_write(slave->sdev, addr, &reg, 1);
if (rc) {
pr_err("BIF slave register write failed, rc=%d\n", rc);
goto notifier_unregister;
}
/* Set global interrupt enable if task not in set 0. */
if (task / SLAVE_CTRL_TASKS_PER_SET != 0) {
mask = BIT(0);
addr = SLAVE_CTRL_FUNC_IRQ_EN_ADDR(
slave->sdev->slave_ctrl_function->slave_ctrl_pointer, 0);
rc = _bif_slave_read(slave->sdev, addr, &reg, 1);
if (rc) {
pr_err("BIF slave register read failed, rc=%d\n", rc);
goto notifier_unregister;
}
reg |= mask;
rc = _bif_slave_write(slave->sdev, addr, &reg, 1);
if (rc) {
pr_err("BIF slave register write failed, rc=%d\n", rc);
goto notifier_unregister;
}
}
rc = slave->sdev->bdev->desc->ops->set_bus_state(slave->sdev->bdev,
BIF_BUS_STATE_INTERRUPT);
if (rc) {
pr_err("Could not set BIF bus to interrupt mode, rc=%d\n", rc);
goto notifier_unregister;
}
slave->sdev->bdev->irq_count++;
done:
bif_slave_ctrl_unlock(slave);
return rc;
notifier_unregister:
blocking_notifier_chain_unregister(
&slave->sdev->slave_ctrl_function->irq_notifier_list[task],
nb);
bif_slave_ctrl_unlock(slave);
return rc;
}
EXPORT_SYMBOL(bif_request_irq);
/**
* bif_free_irq() - free a BIF slave IRQ by slave task number
* @slave: BIF slave handle
* @task: BIF task number of the IRQ inside of the slave. This
* corresponds to the slave control channel specified for a given
* BIF function inside of the slave.
* @nb: Notifier block previously registered with this interrupt
*
* This function unregisters a notifier block that was previously registered
* with bif_request_irq().
*
* Returns 0 for success or errno if an error occurred.
*/
int bif_free_irq(struct bif_slave *slave, unsigned int task,
struct notifier_block *nb)
{
int rc;
u16 addr;
u8 reg;
rc = bif_check_task(slave, task);
if (rc) {
pr_err("Invalid slave or task, rc=%d\n", rc);
return rc;
}
bif_slave_ctrl_lock(slave);
/* Disable the interrupt within the slave */
reg = BIT(task % SLAVE_CTRL_TASKS_PER_SET);
addr = SLAVE_CTRL_FUNC_IRQ_CLEAR_ADDR(
slave->sdev->slave_ctrl_function->slave_ctrl_pointer, task);
rc = _bif_slave_write(slave->sdev, addr, &reg, 1);
if (rc) {
pr_err("BIF slave register write failed, rc=%d\n", rc);
goto done;
}
rc = blocking_notifier_chain_unregister(
&slave->sdev->slave_ctrl_function->irq_notifier_list[task], nb);
if (rc) {
pr_err("Notifier unregistration failed, rc=%d\n", rc);
goto done;
}
slave->sdev->bdev->irq_count--;
if (slave->sdev->bdev->irq_count == 0) {
bif_cancel_irq_mode_work(slave->sdev->bdev);
} else if (slave->sdev->bdev->irq_count < 0) {
pr_err("Unbalanced IRQ free.\n");
rc = -EINVAL;
slave->sdev->bdev->irq_count = 0;
}
done:
bif_slave_ctrl_unlock(slave);
return rc;
}
EXPORT_SYMBOL(bif_free_irq);
/**
* bif_trigger_task() - trigger a task within a BIF slave
* @slave: BIF slave handle
* @task: BIF task inside of the slave to trigger. This corresponds to
* the slave control channel specified for a given BIF function
* inside of the slave.
*
* Returns 0 for success or errno if an error occurred.
*/
int bif_trigger_task(struct bif_slave *slave, unsigned int task)
{
int rc;
u16 addr;
u8 reg;
rc = bif_check_task(slave, task);
if (rc) {
pr_err("Invalid slave or task, rc=%d\n", rc);
return rc;
}
bif_slave_ctrl_lock(slave);
/* Trigger the task within the slave. */
reg = BIT(task % SLAVE_CTRL_TASKS_PER_SET);
addr = SLAVE_CTRL_FUNC_TASK_TRIGGER_ADDR(
slave->sdev->slave_ctrl_function->slave_ctrl_pointer, task);
rc = _bif_slave_write(slave->sdev, addr, &reg, 1);
if (rc) {
pr_err("BIF slave register write failed, rc=%d\n", rc);
goto done;
}
done:
bif_slave_ctrl_unlock(slave);
return rc;
}
EXPORT_SYMBOL(bif_trigger_task);
/**
* bif_enable_auto_task() - enable task auto triggering for the specified task
* @slave: BIF slave handle
* @task: BIF task inside of the slave to configure for automatic
* triggering. This corresponds to the slave control channel
* specified for a given BIF function inside of the slave.
*
* Returns 0 for success or errno if an error occurred.
*/
int bif_enable_auto_task(struct bif_slave *slave, unsigned int task)
{
int rc;
if (IS_ERR_OR_NULL(slave)) {
pr_err("Invalid slave pointer=%ld\n", PTR_ERR(slave));
return -EINVAL;
}
bif_slave_ctrl_lock(slave);
rc = _bif_enable_auto_task(slave->sdev, task);
bif_slave_ctrl_unlock(slave);
return rc;
}
EXPORT_SYMBOL(bif_enable_auto_task);
/**
* bif_disable_auto_task() - disable task auto triggering for the specified task
* @slave: BIF slave handle
* @task: BIF task inside of the slave to stop automatic triggering on.
* This corresponds to the slave control channel specified for a
* given BIF function inside of the slave.
*
* This function should be called after bif_enable_auto_task() in a paired
* fashion.
*
* Returns 0 for success or errno if an error occurred.
*/
int bif_disable_auto_task(struct bif_slave *slave, unsigned int task)
{
int rc;
if (IS_ERR_OR_NULL(slave)) {
pr_err("Invalid slave pointer=%ld\n", PTR_ERR(slave));
return -EINVAL;
}
bif_slave_ctrl_lock(slave);
rc = _bif_disable_auto_task(slave->sdev, task);
bif_slave_ctrl_unlock(slave);
return rc;
}
EXPORT_SYMBOL(bif_disable_auto_task);
/**
* bif_task_is_busy() - checks the state of a BIF slave task
* @slave: BIF slave handle
* @task: BIF task inside of the slave to trigger. This corresponds to
* the slave control channel specified for a given BIF function
* inside of the slave.
*
* Returns 1 if the task is busy, 0 if it is not busy, and errno on error.
*/
int bif_task_is_busy(struct bif_slave *slave, unsigned int task)
{
int rc;
if (IS_ERR_OR_NULL(slave)) {
pr_err("Invalid slave pointer=%ld\n", PTR_ERR(slave));
return -EINVAL;
}
bif_slave_ctrl_lock(slave);
rc = _bif_task_is_busy(slave->sdev, task);
bif_slave_ctrl_unlock(slave);
return rc;
}
EXPORT_SYMBOL(bif_task_is_busy);
static int bif_slave_notify_irqs(struct bif_slave_dev *sdev, int set, u8 val)
{
int rc = 0;
int i, task;
for (i = 0; i < SLAVE_CTRL_TASKS_PER_SET; i++) {
if (val & (1 << i)) {
task = set * SLAVE_CTRL_TASKS_PER_SET + i;
rc = blocking_notifier_call_chain(
&sdev->slave_ctrl_function->irq_notifier_list[task],
task, sdev->bdev);
rc = notifier_to_errno(rc);
if (rc)
pr_err("Notification failed for task %d\n",
task);
}
}
return rc;
}
static int bif_slave_handle_irq(struct bif_slave_dev *sdev)
{
struct bif_ctrl_dev *bdev = sdev->bdev;
bool resp = false;
int rc = 0;
int i;
u16 addr;
u8 reg;
mutex_lock(&sdev->bdev->mutex);
bif_cancel_irq_mode_work(sdev->bdev);
rc = bif_select_slave(sdev);
if (rc) {
pr_err("Could not select slave, rc=%d\n", rc);
goto done;
}
/* Check overall slave interrupt status. */
rc = bdev->desc->ops->bus_transaction_query(bdev, BIF_TRANS_BC,
BIF_CMD_ISTS, &resp);
if (rc) {
pr_err("Could not query slave interrupt status, rc=%d\n", rc);
goto done;
}
if (resp) {
for (i = 0; i < sdev->slave_ctrl_function->task_count
/ SLAVE_CTRL_TASKS_PER_SET; i++) {
addr = sdev->slave_ctrl_function->slave_ctrl_pointer
+ 4 * i + 1;
rc = _bif_slave_read(sdev, addr, &reg, 1);
if (rc) {
pr_err("BIF slave register read failed, rc=%d\n",
rc);
goto done;
}
/* Ensure that interrupts are pending in the set. */
if (reg != 0x00) {
/*
* Release mutex before notifying consumers so
* that they can use the bus.
*/
mutex_unlock(&sdev->bdev->mutex);
rc = bif_slave_notify_irqs(sdev, i, reg);
if (rc) {
pr_err("BIF slave irq notification failed, rc=%d\n",
rc);
goto notification_failed;
}
mutex_lock(&sdev->bdev->mutex);
rc = bif_select_slave(sdev);
if (rc) {
pr_err("Could not select slave, rc=%d\n",
rc);
goto done;
}
/* Clear all interrupts in this set. */
rc = _bif_slave_write(sdev, addr, &reg, 1);
if (rc) {
pr_err("BIF slave register write failed, rc=%d\n",
rc);
goto done;
}
}
}
}
done:
bif_schedule_irq_mode_work(sdev->bdev);
mutex_unlock(&sdev->bdev->mutex);
notification_failed:
if (rc == 0)
rc = resp;
return rc;
}
/**
* bif_ctrl_notify_slave_irq() - notify the BIF framework that a slave interrupt
* was received by a BIF controller
* @bdev: BIF controller device pointer
*
* This function should only be called from a BIF controller driver.
*
* Returns 0 for success or errno if an error occurred.
*/
int bif_ctrl_notify_slave_irq(struct bif_ctrl_dev *bdev)
{
struct bif_slave_dev *sdev;
int rc = 0, handled = 0;
if (IS_ERR_OR_NULL(bdev))
return -EINVAL;
mutex_lock(&bif_sdev_list_mutex);
list_for_each_entry(sdev, &bif_sdev_list, list) {
if (sdev->bdev == bdev && sdev->present) {
rc = bif_slave_handle_irq(sdev);
if (rc < 0) {
pr_err("Could not handle BIF slave irq, rc=%d\n",
rc);
break;
}
handled += rc;
}
}
mutex_unlock(&bif_sdev_list_mutex);
if (handled == 0)
pr_info("Spurious BIF slave interrupt detected.\n");
if (rc > 0)
rc = 0;
return rc;
}
EXPORT_SYMBOL(bif_ctrl_notify_slave_irq);
/**
* bif_ctrl_notify_battery_changed() - notify the BIF framework that a battery
* pack has been inserted or removed
* @bdev: BIF controller device pointer
*
* This function should only be called from a BIF controller driver.
*
* Returns 0 for success or errno if an error occurred.
*/
int bif_ctrl_notify_battery_changed(struct bif_ctrl_dev *bdev)
{
int rc = 0;
int present;
if (IS_ERR_OR_NULL(bdev))
return -EINVAL;
if (bdev->desc->ops->get_battery_presence) {
present = bdev->desc->ops->get_battery_presence(bdev);
if (present < 0) {
pr_err("Could not determine battery presence, rc=%d\n",
rc);
return rc;
}
if (bdev->battery_present == !!present)
return 0;
bdev->battery_present = present;
rc = blocking_notifier_call_chain(&bdev->bus_change_notifier,
present ? BIF_BUS_EVENT_BATTERY_INSERTED
: BIF_BUS_EVENT_BATTERY_REMOVED, bdev);
if (rc)
pr_err("Call chain noification failed, rc=%d\n", rc);
}
return rc;
}
EXPORT_SYMBOL(bif_ctrl_notify_battery_changed);
/**
* bif_ctrl_signal_battery_changed() - notify the BIF framework that a battery
* pack has been inserted or removed
* @ctrl: BIF controller consumer handle
*
* This function should only be called by a BIF consumer driver on systems where
* the BIF controller driver is unable to determine when a battery is inserted
* or removed.
*
* Returns 0 for success or errno if an error occurred.
*/
int bif_ctrl_signal_battery_changed(struct bif_ctrl *ctrl)
{
if (IS_ERR_OR_NULL(ctrl))
return -EINVAL;
return bif_ctrl_notify_battery_changed(ctrl->bdev);
}
EXPORT_SYMBOL(bif_ctrl_signal_battery_changed);
/**
* bif_ctrl_notifier_register() - register a notifier block to be called when
* a battery pack is inserted or removed
* @ctrl: BIF controller consumer handle
*
* The value passed into the notifier when it is called is one of
* enum bif_bus_event.
*
* Returns 0 for success or errno if an error occurred.
*/
int bif_ctrl_notifier_register(struct bif_ctrl *ctrl, struct notifier_block *nb)
{
int rc;
if (IS_ERR_OR_NULL(ctrl))
return -EINVAL;
rc = blocking_notifier_chain_register(&ctrl->bdev->bus_change_notifier,
nb);
if (rc)
pr_err("Notifier registration failed, rc=%d\n", rc);
return rc;
}
EXPORT_SYMBOL(bif_ctrl_notifier_register);
/**
* bif_ctrl_notifier_unregister() - unregister a battery status change notifier
* block that was previously registered
* @ctrl: BIF controller consumer handle
*
* Returns 0 for success or errno if an error occurred.
*/
int bif_ctrl_notifier_unregister(struct bif_ctrl *ctrl,
struct notifier_block *nb)
{
int rc;
if (IS_ERR_OR_NULL(ctrl))
return -EINVAL;
rc =
blocking_notifier_chain_unregister(&ctrl->bdev->bus_change_notifier,
nb);
if (rc)
pr_err("Notifier unregistration failed, rc=%d\n", rc);
return rc;
}
EXPORT_SYMBOL(bif_ctrl_notifier_unregister);
/**
* bif_get_bus_handle() - returns the BIF controller consumer handle associated
* with a BIF slave handle
* @slave: BIF slave handle
*
* Note, bif_ctrl_put() should never be called for the pointer output by
* bif_get_bus_handle().
*/
struct bif_ctrl *bif_get_bus_handle(struct bif_slave *slave)
{
if (IS_ERR_OR_NULL(slave))
return ERR_PTR(-EINVAL);
return &slave->ctrl;
}
EXPORT_SYMBOL(bif_get_bus_handle);
/**
* bif_ctrl_count() - returns the number of registered BIF controllers
*/
int bif_ctrl_count(void)
{
struct bif_ctrl_dev *bdev;
int count = 0;
mutex_lock(&bif_ctrl_list_mutex);
list_for_each_entry(bdev, &bif_ctrl_list, list) {
count++;
}
mutex_unlock(&bif_ctrl_list_mutex);
return count;
}
EXPORT_SYMBOL(bif_ctrl_count);
/**
* bif_ctrl_get_by_id() - get a handle for the id'th BIF controller registered
* in the system
* @id: Arbitrary number associated with the BIF bus in the system
*
* id must be in the range [0, bif_ctrl_count() - 1]. This function should only
* need to be called by a BIF consumer that is unable to link to a given BIF
* controller via a device tree binding.
*
* Returns a BIF controller consumer handle if successful or an ERR_PTR if not.
*/
struct bif_ctrl *bif_ctrl_get_by_id(unsigned int id)
{
struct bif_ctrl_dev *bdev;
struct bif_ctrl_dev *bdev_found = NULL;
struct bif_ctrl *ctrl = ERR_PTR(-ENODEV);
mutex_lock(&bif_ctrl_list_mutex);
list_for_each_entry(bdev, &bif_ctrl_list, list) {
if (id == 0) {
bdev_found = bdev;
break;
}
id--;
}
mutex_unlock(&bif_ctrl_list_mutex);
if (bdev_found) {
ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
if (!ctrl) {
pr_err("Bus handle allocation failed\n");
ctrl = ERR_PTR(-ENOMEM);
} else {
ctrl->bdev = bdev_found;
}
}
return ctrl;
}
EXPORT_SYMBOL(bif_ctrl_get_by_id);
/**
* bif_ctrl_get() - get a handle for the BIF controller that is linked to the
* consumer device in the device tree
* @consumer_dev: Pointer to the consumer's device
*
* In order to use this function, the BIF consumer's device must specify the
* "qcom,bif-ctrl" property in its device tree node which points to a BIF
* controller device node.
*
* Returns a BIF controller consumer handle if successful or an ERR_PTR if not.
* If the BIF controller linked to the consumer device has not yet probed, then
* ERR_PTR(-EPROBE_DEFER) is returned.
*/
struct bif_ctrl *bif_ctrl_get(struct device *consumer_dev)
{
struct device_node *ctrl_node = NULL;
struct bif_ctrl_dev *bdev_found = NULL;
struct bif_ctrl *ctrl = ERR_PTR(-EPROBE_DEFER);
struct bif_ctrl_dev *bdev = NULL;
if (!consumer_dev || !consumer_dev->of_node) {
pr_err("Invalid device node\n");
return ERR_PTR(-EINVAL);
}
ctrl_node = of_parse_phandle(consumer_dev->of_node, "qcom,bif-ctrl", 0);
if (!ctrl_node) {
pr_err("Could not find qcom,bif-ctrl property in %s\n",
consumer_dev->of_node->full_name);
return ERR_PTR(-ENXIO);
}
mutex_lock(&bif_ctrl_list_mutex);
list_for_each_entry(bdev, &bif_ctrl_list, list) {
if (bdev->ctrl_dev && bdev->ctrl_dev->of_node == ctrl_node) {
bdev_found = bdev;
break;
}
}
mutex_unlock(&bif_ctrl_list_mutex);
if (bdev_found) {
ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
if (!ctrl) {
pr_err("Bus handle allocation failed\n");
ctrl = ERR_PTR(-ENOMEM);
} else {
ctrl->bdev = bdev_found;
}
}
return ctrl;
}
EXPORT_SYMBOL(bif_ctrl_get);
/**
* bif_ctrl_put() - frees a BIF controller handle
* @ctrl: BIF controller consumer handle
*/
void bif_ctrl_put(struct bif_ctrl *ctrl)
{
if (!IS_ERR_OR_NULL(ctrl) && ctrl->exclusive_lock)
mutex_unlock(&ctrl->bdev->mutex);
kfree(ctrl);
}
EXPORT_SYMBOL(bif_ctrl_put);
static bool bif_slave_object_match(const struct bif_object *object,
const struct bif_match_criteria *criteria)
{
return (object->type == criteria->obj_type)
&& (object->version == criteria->obj_version
|| !(criteria->match_mask & BIF_MATCH_OBJ_VERSION))
&& (object->manufacturer_id == criteria->obj_manufacturer_id
|| !(criteria->match_mask & BIF_MATCH_OBJ_MANUFACTURER_ID));
}
/*
* Returns true if all parameters are matched, otherwise false.
* function_type and function_version mean that their exists some function in
* the slave which has the specified type and subtype. ctrl == NULL is treated
* as a wildcard.
*/
static bool bif_slave_match(struct bif_ctrl *ctrl,
struct bif_slave_dev *sdev, const struct bif_match_criteria *criteria)
{
int i, type, version;
struct bif_object *object;
bool function_found = false;
bool object_found = false;
if (ctrl && (ctrl->bdev != sdev->bdev))
return false;
if (!sdev->present
&& (!(criteria->match_mask & BIF_MATCH_IGNORE_PRESENCE)
|| ((criteria->match_mask & BIF_MATCH_IGNORE_PRESENCE)
&& !criteria->ignore_presence)))
return false;
if ((criteria->match_mask & BIF_MATCH_MANUFACTURER_ID)
&& sdev->l1_data.manufacturer_id != criteria->manufacturer_id)
return false;
if ((criteria->match_mask & BIF_MATCH_PRODUCT_ID)
&& sdev->l1_data.product_id != criteria->product_id)
return false;
if (criteria->match_mask & BIF_MATCH_FUNCTION_TYPE) {
if (!sdev->function_directory)
return false;
for (i = 0; i < sdev->l1_data.length / 4; i++) {
type = sdev->function_directory[i].function_type;
version = sdev->function_directory[i].function_version;
if (type == criteria->function_type &&
(version == criteria->function_version
|| !(criteria->match_mask
& BIF_MATCH_FUNCTION_VERSION))) {
function_found = true;
break;
}
}
if (!function_found)
return false;
}
if (criteria->match_mask & BIF_MATCH_OBJ_TYPE) {
if (!sdev->nvm_function)
return false;
bif_ctrl_lock(ctrl);
list_for_each_entry(object, &sdev->nvm_function->object_list,
list) {
if (bif_slave_object_match(object, criteria)) {
object_found = true;
break;
}
}
bif_ctrl_unlock(ctrl);
if (!object_found)
return false;
}
return true;
}
/**
* bif_slave_match_count() - returns the number of slaves associated with the
* specified BIF controller which fit the matching
* criteria
* @ctrl: BIF controller consumer handle
* @match_criteria: Matching criteria used to filter slaves
*/
int bif_slave_match_count(struct bif_ctrl *ctrl,
const struct bif_match_criteria *match_criteria)
{
struct bif_slave_dev *sdev;
int count = 0;
mutex_lock(&bif_sdev_list_mutex);
list_for_each_entry(sdev, &bif_sdev_list, list) {
if (bif_slave_match(ctrl, sdev, match_criteria))
count++;
}
mutex_unlock(&bif_sdev_list_mutex);
return count;
}
EXPORT_SYMBOL(bif_slave_match_count);
/**
* bif_slave_match_get() - get a slave handle for the id'th slave associated
* with the specified BIF controller which fits the
* matching criteria
* @ctrl: BIF controller consumer handle
* @id: Index into the set of matching slaves
* @match_criteria: Matching criteria used to filter slaves
*
* id must be in the range [0, bif_slave_match_count(ctrl, match_criteria) - 1].
*
* Returns a BIF slave handle if successful or an ERR_PTR if not.
*/
struct bif_slave *bif_slave_match_get(struct bif_ctrl *ctrl,
unsigned int id, const struct bif_match_criteria *match_criteria)
{
struct bif_slave_dev *sdev;
struct bif_slave *slave = ERR_PTR(-ENODEV);
struct bif_slave_dev *sdev_found = NULL;
int count = 0;
mutex_lock(&bif_sdev_list_mutex);
list_for_each_entry(sdev, &bif_sdev_list, list) {
if (bif_slave_match(ctrl, sdev, match_criteria))
count++;
if (count == id + 1) {
sdev_found = sdev;
break;
}
}
mutex_unlock(&bif_sdev_list_mutex);
if (sdev_found) {
slave = kzalloc(sizeof(*slave), GFP_KERNEL);
if (!slave) {
pr_err("Slave allocation failed\n");
slave = ERR_PTR(-ENOMEM);
} else {
slave->sdev = sdev_found;
slave->ctrl.bdev = sdev_found->bdev;
}
}
return slave;
}
EXPORT_SYMBOL(bif_slave_match_get);
/**
* bif_slave_put() - frees a BIF slave handle
* @slave: BIF slave handle
*/
void bif_slave_put(struct bif_slave *slave)
{
if (!IS_ERR_OR_NULL(slave) && slave->ctrl.exclusive_lock)
mutex_unlock(&slave->sdev->bdev->mutex);
kfree(slave);
}
EXPORT_SYMBOL(bif_slave_put);
/**
* bif_slave_find_function() - get the function pointer and version of a
* BIF function if it is present on the specified slave
* @slave: BIF slave handle
* @function: BIF function to search for inside of the slave
* @version: If the function is found, then 'version' is set to the
* version value of the function
* @function_pointer: If the function is found, then 'function_pointer' is set
* to the BIF slave address of the function
*
* Returns 0 for success or errno if an error occurred. If the function is not
* found in the slave, then -ENODEV is returned.
*/
int bif_slave_find_function(struct bif_slave *slave, u8 function, u8 *version,
u16 *function_pointer)
{
int rc = -ENODEV;
struct bif_ddb_l2_data *func;
int i;
if (IS_ERR_OR_NULL(slave) || IS_ERR_OR_NULL(version)
|| IS_ERR_OR_NULL(function_pointer)) {
pr_err("Invalid pointer input.\n");
return -EINVAL;
}
func = slave->sdev->function_directory;
for (i = 0; i < slave->sdev->l1_data.length / 4; i++) {
if (function == func[i].function_type) {
*version = func[i].function_version;
*function_pointer = func[i].function_pointer;
rc = 0;
break;
}
}
return rc;
}
EXPORT_SYMBOL(bif_slave_find_function);
static bool bif_object_match(const struct bif_object *object,
const struct bif_obj_match_criteria *criteria)
{
return (object->type == criteria->type
|| !(criteria->match_mask & BIF_OBJ_MATCH_TYPE))
&& (object->version == criteria->version
|| !(criteria->match_mask & BIF_OBJ_MATCH_VERSION))
&& (object->manufacturer_id == criteria->manufacturer_id
|| !(criteria->match_mask & BIF_OBJ_MATCH_MANUFACTURER_ID));
}
/**
* bif_object_match_count() - returns the number of objects associated with the
* specified BIF slave which fit the matching criteria
* @slave: BIF slave handle
* @match_criteria: Matching criteria used to filter objects
*/
int bif_object_match_count(struct bif_slave *slave,
const struct bif_obj_match_criteria *match_criteria)
{
struct bif_object *object;
int count = 0;
if (IS_ERR_OR_NULL(slave) || IS_ERR_OR_NULL(match_criteria)) {
pr_err("Invalid pointer input.\n");
return -EINVAL;
}
if (!slave->sdev->nvm_function)
return 0;
bif_slave_ctrl_lock(slave);
list_for_each_entry(object, &slave->sdev->nvm_function->object_list,
list) {
if (bif_object_match(object, match_criteria))
count++;
}
bif_slave_ctrl_unlock(slave);
return count;
}
EXPORT_SYMBOL(bif_object_match_count);
/**
* bif_object_match_get() - get a BIF object handle for the id'th object found
* in the non-volatile memory of the specified BIF slave
* which fits the matching criteria
* @slave: BIF slave handle
* @id: Index into the set of matching objects
* @match_criteria: Matching criteria used to filter objects
*
* id must be in range [0, bif_object_match_count(slave, match_criteria) - 1].
*
* Returns a BIF object handle if successful or an ERR_PTR if not. This handle
* must be freed using bif_object_put() when it is no longer needed.
*/
struct bif_object *bif_object_match_get(struct bif_slave *slave,
unsigned int id, const struct bif_obj_match_criteria *match_criteria)
{
struct bif_object *object;
struct bif_object *object_found = NULL;
struct bif_object *object_consumer = ERR_PTR(-ENODEV);
int count = 0;
if (IS_ERR_OR_NULL(slave) || IS_ERR_OR_NULL(match_criteria)) {
pr_err("Invalid pointer input.\n");
return ERR_PTR(-EINVAL);
}
if (!slave->sdev->nvm_function)
return object_consumer;
bif_slave_ctrl_lock(slave);
list_for_each_entry(object, &slave->sdev->nvm_function->object_list,
list) {
if (bif_object_match(object, match_criteria))
count++;
if (count == id + 1) {
object_found = object;
break;
}
}
if (object_found) {
object_consumer = kmemdup(object_found,
sizeof(*object_consumer), GFP_KERNEL);
if (!object_consumer) {
pr_err("out of memory\n");
object_consumer = ERR_PTR(-ENOMEM);
goto done;
}
object_consumer->data = kmemdup(object_found->data,
object_found->length - 8, GFP_KERNEL);
if (!object_consumer->data) {
pr_err("out of memory\n");
kfree(object_consumer);
object_consumer = ERR_PTR(-ENOMEM);
goto done;
}
/*
* Use prev pointer in consumer struct to point to original
* struct in the internal linked list.
*/
object_consumer->list.prev = &object_found->list;
}
done:
bif_slave_ctrl_unlock(slave);
return object_consumer;
}
EXPORT_SYMBOL(bif_object_match_get);
/**
* bif_object_put() - frees the memory allocated for a BIF object pointer
* returned by bif_object_match_get()
* @object: BIF object to free
*/
void bif_object_put(struct bif_object *object)
{
if (object)
kfree(object->data);
kfree(object);
}
EXPORT_SYMBOL(bif_object_put);
/* Copies the contents of object into buf following MIPI-BIF formatting. */
static void bif_object_flatten(u8 *buf, const struct bif_object *object)
{
buf[0] = object->type;
buf[1] = object->version;
buf[2] = object->manufacturer_id >> 8;
buf[3] = object->manufacturer_id;
buf[4] = object->length >> 8;
buf[5] = object->length;
memcpy(&buf[6], object->data, object->length - 8);
buf[object->length - 2] = object->crc >> 8;
buf[object->length - 1] = object->crc;
}
/**
* bif_object_write() - writes a new BIF object at the end of the object list in
* the non-volatile memory of a slave
* @slave: BIF slave handle
* @type: Type of the object
* @version: Version of the object
* @manufacturer_id: Manufacturer ID number allocated by MIPI
* @data: Data contained in the object
* @data_len: Length of the data
*
* Returns 0 on success or errno on failure. This function will fail if the NVM
* lock points to an offset after the BIF object list terminator (0x00).
*/
int bif_object_write(struct bif_slave *slave, u8 type, u8 version,
u16 manufacturer_id, const u8 *data, int data_len)
{
struct bif_object *object;
struct bif_object *tail_object;
struct bif_nvm_function *nvm;
int rc;
int add_null = 0;
u16 offset = 0;
u8 *buf;
if (IS_ERR_OR_NULL(slave) || IS_ERR_OR_NULL(data)) {
pr_err("Invalid input pointer\n");
return -EINVAL;
}
nvm = slave->sdev->nvm_function;
if (!nvm) {
pr_err("BIF slave has no NVM function\n");
return -ENODEV;
}
bif_slave_ctrl_lock(slave);
if (nvm->object_count > 0) {
tail_object = list_entry(nvm->object_list.prev,
struct bif_object, list);
offset = tail_object->addr - nvm->nvm_base_address
+ tail_object->length;
}
if (offset < nvm->nvm_lock_offset) {
pr_err("Cannot write BIF object to NVM because the end of the object list is locked (end=%d < lock=%d)\n",
offset, nvm->nvm_lock_offset);
rc = -EPERM;
goto error_unlock;
} else if (offset + data_len + 8 > nvm->nvm_size) {
pr_err("Cannot write BIF object to NVM because there is not enough remaining space (size=%d > remaining=%d)\n",
data_len + 8, nvm->nvm_size - offset);
rc = -EINVAL;
goto error_unlock;
}
if (offset + data_len + 8 < nvm->nvm_size)
add_null = 1;
object = kzalloc(sizeof(*object), GFP_KERNEL);
if (!object) {
pr_err("kzalloc failed\n");
rc = -ENOMEM;
goto error_unlock;
}
object->data = kzalloc(data_len, GFP_KERNEL);
if (!object->data) {
pr_err("kzalloc failed\n");
rc = -ENOMEM;
goto free_object;
}
buf = kzalloc(data_len + 8 + add_null, GFP_KERNEL);
if (!buf) {
pr_err("kzalloc failed\n");
rc = -ENOMEM;
goto free_data;
}
object->type = type;
object->version = version;
object->manufacturer_id = manufacturer_id;
object->length = data_len + 8;
memcpy(object->data, data, data_len);
object->crc = bif_object_crc_ccitt(object);
object->addr = offset + nvm->nvm_base_address;
bif_object_flatten(buf, object);
if (add_null)
buf[object->length] = BIF_OBJ_END_OF_LIST;
rc = _bif_slave_nvm_raw_write(slave->sdev, offset, buf,
object->length + add_null);
if (rc < 0) {
pr_err("NVM write failed, rc=%d\n", rc);
kfree(buf);
goto free_data;
}
kfree(buf);
list_add_tail(&object->list, &nvm->object_list);
nvm->object_count++;
bif_slave_ctrl_unlock(slave);
return rc;
free_data:
kfree(object->data);
free_object:
kfree(object);
error_unlock:
bif_slave_ctrl_unlock(slave);
return rc;
}
EXPORT_SYMBOL(bif_object_write);
/*
* Returns a pointer to the internal object referenced by a consumer object
* if it exists. Returns NULL if the internal object cannot be found.
*/
static struct bif_object *bif_object_consumer_search(
struct bif_nvm_function *nvm, const struct bif_object *consumer_object)
{
struct bif_object *object = NULL;
struct bif_object *search_object;
/*
* Internal struct in object linked list is pointed to by consumer
* object list.prev.
*/
search_object = list_entry(consumer_object->list.prev,
struct bif_object, list);
list_for_each_entry(object, &nvm->object_list, list) {
if (object == search_object)
break;
}
if (object != search_object)
return NULL;
return object;
}
/**
* bif_object_overwrite() - overwrites an existing BIF object found in the
* non-volatile memory of a slave
* @slave: BIF slave handle
* @object: Existing object in the slave to overwrite
* @type: Type of the object
* @version: Version of the object
* @manufacturer_id: Manufacturer ID number allocated by MIPI
* @data: Data contained in the object
* @data_len: Length of the data
*
* Returns 0 on success or errno on failure. The data stored within 'object'
* is updated to the new values upon success. The new data written to the
* object must have exactly the same length as the old data (i.e.
* data_len == object->length - 8).
*
* This function will fail if the NVM lock points to an offset after the
* beginning of the existing BIF object.
*/
int bif_object_overwrite(struct bif_slave *slave,
struct bif_object *object, u8 type, u8 version,
u16 manufacturer_id, const u8 *data, int data_len)
{
struct bif_object *edit_object = NULL;
struct bif_nvm_function *nvm;
int rc;
u16 crc;
u8 *buf;
if (IS_ERR_OR_NULL(slave) || IS_ERR_OR_NULL(object)
|| IS_ERR_OR_NULL(data)) {
pr_err("Invalid input pointer\n");
return -EINVAL;
}
nvm = slave->sdev->nvm_function;
if (!nvm) {
pr_err("BIF slave has no NVM function\n");
return -ENODEV;
}
if (data_len + 8 != object->length) {
pr_err("New data length=%d is different from existing length=%d\n",
data_len, object->length - 8);
return -EINVAL;
}
bif_slave_ctrl_lock(slave);
edit_object = bif_object_consumer_search(nvm, object);
if (!edit_object) {
pr_err("BIF object not found within slave\n");
rc = -EINVAL;
goto error_unlock;
}
if (edit_object->addr - nvm->nvm_base_address < nvm->nvm_lock_offset) {
pr_err("Cannot overwrite BIF object in NVM because some portion of it is locked\n");
rc = -EPERM;
goto error_unlock;
}
buf = kzalloc(data_len + 8, GFP_KERNEL);
if (!buf) {
pr_err("kzalloc failed\n");
rc = -ENOMEM;
goto error_unlock;
}
buf[0] = type;
buf[1] = version;
buf[2] = manufacturer_id >> 8;
buf[3] = manufacturer_id;
buf[4] = (data_len + 8) >> 8;
buf[5] = data_len + 8;
memcpy(&buf[6], data, data_len);
crc = bif_crc_ccitt(buf, data_len + 6);
buf[data_len + 6] = crc >> 8;
buf[data_len + 7] = crc;
rc = _bif_slave_nvm_raw_write(slave->sdev,
object->addr - nvm->nvm_base_address, buf, data_len + 8);
if (rc < 0) {
pr_err("NVM write failed, rc=%d\n", rc);
kfree(buf);
goto error_unlock;
}
kfree(buf);
/* Update internal object struct. */
edit_object->type = type;
edit_object->version = version;
edit_object->manufacturer_id = manufacturer_id;
edit_object->length = data_len + 8;
memcpy(edit_object->data, data, data_len);
edit_object->crc = crc;
/* Update consumer object struct. */
object->type = type;
object->version = version;
object->manufacturer_id = manufacturer_id;
object->length = data_len + 8;
memcpy(object->data, data, data_len);
object->crc = crc;
error_unlock:
bif_slave_ctrl_unlock(slave);
return rc;
}
EXPORT_SYMBOL(bif_object_overwrite);
/**
* bif_object_delete() - deletes an existing BIF object found in the
* non-volatile memory of a slave. Objects found in the
* object list in the NVM of the slave are shifted forward
* in order to fill the hole left by the deleted object
* @slave: BIF slave handle
* @object: Existing object in the slave to delete
*
* Returns 0 on success or errno on failure. bif_object_put() must still be
* called after this function in order to free the memory in the consumer
* 'object' struct pointer.
*
* This function will fail if the NVM lock points to an offset after the
* beginning of the existing BIF object.
*/
int bif_object_delete(struct bif_slave *slave, const struct bif_object *object)
{
struct bif_object *del_object = NULL;
struct bif_object *tail_object;
struct bif_nvm_function *nvm;
bool found = false;
int pos = 0;
int rc;
u8 *buf;
if (IS_ERR_OR_NULL(slave) || IS_ERR_OR_NULL(object)) {
pr_err("Invalid input pointer\n");
return -EINVAL;
}
nvm = slave->sdev->nvm_function;
if (!nvm) {
pr_err("BIF slave has no NVM function\n");
return -ENODEV;
}
bif_slave_ctrl_lock(slave);
del_object = bif_object_consumer_search(nvm, object);
if (!del_object) {
pr_err("BIF object not found within slave\n");
rc = -EINVAL;
goto error_unlock;
}
if (del_object->addr - nvm->nvm_base_address < nvm->nvm_lock_offset) {
pr_err("Cannot delete BIF object in NVM because some portion of it is locked\n");
rc = -EPERM;
goto error_unlock;
}
buf = kmalloc(nvm->nvm_size, GFP_KERNEL);
if (!buf) {
pr_err("kzalloc failed\n");
rc = -ENOMEM;
goto error_unlock;
}
/*
* Copy the contents of objects after the one to be deleted into a flat
* array.
*/
list_for_each_entry(tail_object, &nvm->object_list, list) {
if (found) {
bif_object_flatten(&buf[pos], tail_object);
pos += tail_object->length;
} else if (tail_object == del_object) {
found = true;
}
}
/* Add the list terminator. */
buf[pos++] = BIF_OBJ_END_OF_LIST;
rc = _bif_slave_nvm_raw_write(slave->sdev,
del_object->addr - nvm->nvm_base_address, buf, pos);
if (rc < 0) {
pr_err("NVM write failed, rc=%d\n", rc);
kfree(buf);
goto error_unlock;
}
kfree(buf);
/* Update the addresses of the objects after the one to be deleted. */
found = false;
list_for_each_entry(tail_object, &nvm->object_list, list) {
if (found)
tail_object->addr -= del_object->length;
else if (tail_object == del_object)
found = true;
}
list_del(&del_object->list);
kfree(del_object->data);
kfree(del_object);
nvm->object_count--;
error_unlock:
bif_slave_ctrl_unlock(slave);
return rc;
}
EXPORT_SYMBOL(bif_object_delete);
/**
* bif_slave_read() - read contiguous memory values from a BIF slave
* @slave: BIF slave handle
* @addr: BIF slave address to begin reading at
* @buf: Buffer to fill with memory values
* @len: Number of byte to read
*
* Returns 0 for success or errno if an error occurred.
*/
int bif_slave_read(struct bif_slave *slave, u16 addr, u8 *buf, int len)
{
int rc;
if (IS_ERR_OR_NULL(slave) || IS_ERR_OR_NULL(buf)) {
pr_err("Invalid pointer input.\n");
return -EINVAL;
}
bif_slave_ctrl_lock(slave);
rc = _bif_slave_read(slave->sdev, addr, buf, len);
if (rc)
pr_err("BIF slave read failed, rc=%d\n", rc);
bif_slave_ctrl_unlock(slave);
return rc;
}
EXPORT_SYMBOL(bif_slave_read);
/**
* bif_slave_write() - write contiguous memory values to a BIF slave
* @slave: BIF slave handle
* @addr: BIF slave address to begin writing at
* @buf: Buffer containing values to write
* @len: Number of byte to write
*
* Returns 0 for success or errno if an error occurred.
*/
int bif_slave_write(struct bif_slave *slave, u16 addr, u8 *buf, int len)
{
int rc;
if (IS_ERR_OR_NULL(slave) || IS_ERR_OR_NULL(buf)) {
pr_err("Invalid pointer input.\n");
return -EINVAL;
}
bif_slave_ctrl_lock(slave);
rc = _bif_slave_write(slave->sdev, addr, buf, len);
if (rc)
pr_err("BIF slave write failed, rc=%d\n", rc);
bif_slave_ctrl_unlock(slave);
return rc;
}
EXPORT_SYMBOL(bif_slave_write);
/**
* bif_slave_nvm_raw_read() - read contiguous memory values from a BIF slave's
* non-volatile memory (NVM)
* @slave: BIF slave handle
* @offset: Offset from the beginning of BIF slave NVM to begin reading at
* @buf: Buffer to fill with memory values
* @len: Number of byte to read
*
* Returns 0 for success or errno if an error occurred.
*/
int bif_slave_nvm_raw_read(struct bif_slave *slave, u16 offset, u8 *buf,
int len)
{
if (IS_ERR_OR_NULL(slave)) {
pr_err("Invalid slave pointer=%ld\n", PTR_ERR(slave));
return -EINVAL;
} else if (IS_ERR_OR_NULL(buf)) {
pr_err("Invalid buffer pointer=%ld\n", PTR_ERR(buf));
return -EINVAL;
} else if (!slave->sdev->nvm_function) {
pr_err("BIF slave has no NVM function\n");
return -ENODEV;
} else if (offset + len > slave->sdev->nvm_function->nvm_size) {
pr_err("read offset + len = %d > NVM size = %d\n",
offset + len, slave->sdev->nvm_function->nvm_size);
return -EINVAL;
}
return bif_slave_read(slave,
slave->sdev->nvm_function->nvm_base_address + offset, buf, len);
}
EXPORT_SYMBOL(bif_slave_nvm_raw_read);
/**
* bif_slave_nvm_raw_write() - write contiguous memory values to a BIF slave's
* non-volatile memory (NVM)
* @slave: BIF slave handle
* @offset: Offset from the beginning of BIF slave NVM to begin writing at
* @buf: Buffer containing values to write
* @len: Number of byte to write
*
* Note that this function does *not* respect the MIPI-BIF object data
* formatting specification. It can cause corruption of the object data list
* stored in NVM if used improperly.
*
* Returns 0 for success or errno if an error occurred.
*/
int bif_slave_nvm_raw_write(struct bif_slave *slave, u16 offset, u8 *buf,
int len)
{
int rc;
if (IS_ERR_OR_NULL(slave)) {
pr_err("Invalid slave pointer=%ld\n", PTR_ERR(slave));
return -EINVAL;
} else if (IS_ERR_OR_NULL(buf)) {
pr_err("Invalid buffer pointer=%ld\n", PTR_ERR(buf));
return -EINVAL;
}
bif_slave_ctrl_lock(slave);
rc = _bif_slave_nvm_raw_write(slave->sdev, offset, buf, len);
bif_slave_ctrl_unlock(slave);
return rc;
}
EXPORT_SYMBOL(bif_slave_nvm_raw_write);
/**
* bif_slave_is_present() - check if a slave is currently physically present
* in the system
* @slave: BIF slave handle
*
* Returns 1 if the slave is present, 0 if the slave is not present, or errno
* if an error occurred.
*
* This function can be used by BIF consumer drivers to check if their slave
* handles are still meaningful after battery reinsertion.
*/
int bif_slave_is_present(struct bif_slave *slave)
{
if (IS_ERR_OR_NULL(slave)) {
pr_err("Invalid pointer input.\n");
return -EINVAL;
}
return slave->sdev->present;
}
EXPORT_SYMBOL(bif_slave_is_present);
/**
* bif_slave_is_selected() - check if a slave is currently selected on the BIF
* bus
* @slave: BIF slave handle
*
* Returns 1 if the slave is selected, 0 if the slave is not selected, or errno
* if an error occurred.
*
* This function should not be required under normal circumstances since the
* bif-core framework ensures that slaves are always selected when needed.
* It would be most useful when used as a helper in conjunction with
* bif_ctrl_bus_lock() and the raw transaction functions.
*/
int bif_slave_is_selected(struct bif_slave *slave)
{
int rc;
if (IS_ERR_OR_NULL(slave)) {
pr_err("Invalid pointer input.\n");
return -EINVAL;
}
if (slave->sdev->bdev->selected_sdev != slave->sdev)
return false;
bif_slave_ctrl_lock(slave);
rc = bif_is_slave_selected(slave->sdev->bdev);
bif_slave_ctrl_unlock(slave);
return rc;
}
EXPORT_SYMBOL(bif_slave_is_selected);
/**
* bif_slave_select() - select a slave on the BIF bus
* @slave: BIF slave handle
*
* Returns 0 on success or errno if an error occurred.
*
* This function should not be required under normal circumstances since the
* bif-core framework ensures that slaves are always selected when needed.
* It would be most useful when used as a helper in conjunction with
* bif_ctrl_bus_lock() and the raw transaction functions.
*/
int bif_slave_select(struct bif_slave *slave)
{
int rc;
if (IS_ERR_OR_NULL(slave)) {
pr_err("Invalid pointer input.\n");
return -EINVAL;
}
bif_slave_ctrl_lock(slave);
slave->sdev->bdev->selected_sdev = NULL;
rc = bif_select_slave(slave->sdev);
bif_slave_ctrl_unlock(slave);
return rc;
}
EXPORT_SYMBOL(bif_slave_select);
/**
* bif_ctrl_raw_transaction() - perform a raw BIF transaction on the bus which
* expects no slave response
* @ctrl: BIF controller consumer handle
* @transaction: BIF transaction to carry out. This should be one of the
* values in enum bif_transaction.
* @data: 8-bit data to use in the transaction. The meaning of
* this data depends upon the transaction that is to be
* performed.
*
* When performing a bus command (BC) transaction, values in enum
* bif_bus_command may be used for the data parameter. Additional manufacturer
* specific values may also be used in a BC transaction.
*
* Returns 0 on success or errno if an error occurred.
*
* This function should only need to be used when BIF transactions are required
* that are not handled by the bif-core directly.
*/
int bif_ctrl_raw_transaction(struct bif_ctrl *ctrl, int transaction, u8 data)
{
int rc;
if (IS_ERR_OR_NULL(ctrl)) {
pr_err("Invalid pointer input.\n");
return -EINVAL;
}
bif_ctrl_lock(ctrl);
rc = ctrl->bdev->desc->ops->bus_transaction(ctrl->bdev, transaction,
data);
if (rc)
pr_err("BIF bus transaction failed, rc=%d\n", rc);
bif_ctrl_unlock(ctrl);
return rc;
}
EXPORT_SYMBOL(bif_ctrl_raw_transaction);
/**
* bif_ctrl_raw_transaction_read() - perform a raw BIF transaction on the bus
* which expects an RD or TACK slave response word
* @ctrl: BIF controller consumer handle
* @transaction: BIF transaction to carry out. This should be one of the
* values in enum bif_transaction.
* @data: 8-bit data to use in the transaction. The meaning of
* this data depends upon the transaction that is to be
* performed.
* @response: Pointer to an integer which is filled with the 11-bit
* slave response word upon success. The 11-bit format is
* (MSB to LSB) BCF, ACK, EOT, D7-D0.
*
* When performing a bus command (BC) transaction, values in enum
* bif_bus_command may be used for the data parameter. Additional manufacturer
* specific values may also be used in a BC transaction.
*
* Returns 0 on success or errno if an error occurred.
*
* This function should only need to be used when BIF transactions are required
* that are not handled by the bif-core directly.
*/
int bif_ctrl_raw_transaction_read(struct bif_ctrl *ctrl, int transaction,
u8 data, int *response)
{
int rc;
if (IS_ERR_OR_NULL(ctrl) || IS_ERR_OR_NULL(response)) {
pr_err("Invalid pointer input.\n");
return -EINVAL;
}
bif_ctrl_lock(ctrl);
rc = ctrl->bdev->desc->ops->bus_transaction_read(ctrl->bdev,
transaction, data, response);
if (rc)
pr_err("BIF bus transaction failed, rc=%d\n", rc);
bif_ctrl_unlock(ctrl);
return rc;
}
EXPORT_SYMBOL(bif_ctrl_raw_transaction_read);
/**
* bif_ctrl_raw_transaction_query() - perform a raw BIF transaction on the bus
* which expects a BQ slave response
* @ctrl: BIF controller consumer handle
* @transaction: BIF transaction to carry out. This should be one of the
* values in enum bif_transaction.
* @data: 8-bit data to use in the transaction. The meaning of
* this data depends upon the transaction that is to be
* performed.
* @query_response: Pointer to boolean which is set to true if a BQ pulse
* is receieved, or false if no BQ pulse is received before
* timing out.
*
* When performing a bus command (BC) transaction, values in enum
* bif_bus_command may be used for the data parameter. Additional manufacturer
* specific values may also be used in a BC transaction.
*
* Returns 0 on success or errno if an error occurred.
*
* This function should only need to be used when BIF transactions are required
* that are not handled by the bif-core directly.
*/
int bif_ctrl_raw_transaction_query(struct bif_ctrl *ctrl, int transaction,
u8 data, bool *query_response)
{
int rc;
if (IS_ERR_OR_NULL(ctrl) || IS_ERR_OR_NULL(query_response)) {
pr_err("Invalid pointer input.\n");
return -EINVAL;
}
bif_ctrl_lock(ctrl);
rc = ctrl->bdev->desc->ops->bus_transaction_query(ctrl->bdev,
transaction, data, query_response);
if (rc)
pr_err("BIF bus transaction failed, rc=%d\n", rc);
bif_ctrl_unlock(ctrl);
return rc;
}
EXPORT_SYMBOL(bif_ctrl_raw_transaction_query);
/**
* bif_ctrl_bus_lock() - lock the BIF bus of a controller for exclusive access
* @ctrl: BIF controller consumer handle
*
* This function should only need to be called in circumstances where a BIF
* consumer is issuing special BIF bus commands that have strict ordering
* requirements.
*/
void bif_ctrl_bus_lock(struct bif_ctrl *ctrl)
{
if (IS_ERR_OR_NULL(ctrl)) {
pr_err("Invalid controller handle.\n");
return;
}
if (ctrl->exclusive_lock) {
pr_err("BIF bus exclusive lock already held\n");
return;
}
mutex_lock(&ctrl->bdev->mutex);
ctrl->exclusive_lock = true;
bif_cancel_irq_mode_work(ctrl->bdev);
}
EXPORT_SYMBOL(bif_ctrl_bus_lock);
/**
* bif_ctrl_bus_unlock() - lock the BIF bus of a controller that was previously
* locked for exclusive access
* @ctrl: BIF controller consumer handle
*
* This function must only be called after first calling bif_ctrl_bus_lock().
*/
void bif_ctrl_bus_unlock(struct bif_ctrl *ctrl)
{
if (IS_ERR_OR_NULL(ctrl)) {
pr_err("Invalid controller handle.\n");
return;
}
if (!ctrl->exclusive_lock) {
pr_err("BIF bus exclusive lock not already held\n");
return;
}
ctrl->exclusive_lock = false;
bif_schedule_irq_mode_work(ctrl->bdev);
mutex_unlock(&ctrl->bdev->mutex);
}
EXPORT_SYMBOL(bif_ctrl_bus_unlock);
/**
* bif_ctrl_measure_rid() - measure the battery pack Rid pull-down resistance
* in ohms
* @ctrl: BIF controller consumer handle
*
* Returns the resistance of the Rid resistor in ohms if successful or errno
* if an error occurred.
*/
int bif_ctrl_measure_rid(struct bif_ctrl *ctrl)
{
int rc;
if (IS_ERR_OR_NULL(ctrl)) {
pr_err("Invalid controller handle.\n");
return -ENODEV;
}
if (!ctrl->bdev->desc->ops->get_battery_rid) {
pr_err("Cannot measure Rid.\n");
return -ENXIO;
}
bif_ctrl_lock(ctrl);
rc = ctrl->bdev->desc->ops->get_battery_rid(ctrl->bdev);
if (rc < 0)
pr_err("Error during Rid measurement, rc=%d\n", rc);
bif_ctrl_unlock(ctrl);
return rc;
}
EXPORT_SYMBOL(bif_ctrl_measure_rid);
/**
* bif_ctrl_get_bus_period() - get the BIF bus period (tau_bif) in nanoseconds
* @ctrl: BIF controller consumer handle
*
* Returns the currently configured bus period in nanoseconds if successful or
* errno if an error occurred.
*/
int bif_ctrl_get_bus_period(struct bif_ctrl *ctrl)
{
int rc;
if (IS_ERR_OR_NULL(ctrl)) {
pr_err("Invalid controller handle.\n");
return -ENODEV;
}
if (!ctrl->bdev->desc->ops->get_bus_period) {
pr_err("Cannot get the BIF bus period.\n");
return -ENXIO;
}
rc = ctrl->bdev->desc->ops->get_bus_period(ctrl->bdev);
if (rc < 0)
pr_err("Error during bus period retrieval, rc=%d\n", rc);
return rc;
}
EXPORT_SYMBOL(bif_ctrl_get_bus_period);
/**
* bif_ctrl_set_bus_period() - set the BIF bus period (tau_bif) in nanoseconds
* @ctrl: BIF controller consumer handle
* @period_ns: BIF bus period in nanoseconds to use
*
* If the exact period is not supported by the BIF controller hardware, then the
* next larger supported period will be used.
*
* Returns 0 on success or errno if an error occurred.
*/
int bif_ctrl_set_bus_period(struct bif_ctrl *ctrl, int period_ns)
{
int rc;
if (IS_ERR_OR_NULL(ctrl)) {
pr_err("Invalid controller handle.\n");
return -ENODEV;
}
if (!ctrl->bdev->desc->ops->set_bus_period) {
pr_err("Cannot set the BIF bus period.\n");
return -ENXIO;
}
bif_ctrl_lock(ctrl);
rc = ctrl->bdev->desc->ops->set_bus_period(ctrl->bdev, period_ns);
if (rc)
pr_err("Error during bus period configuration, rc=%d\n", rc);
bif_ctrl_unlock(ctrl);
return rc;
}
EXPORT_SYMBOL(bif_ctrl_set_bus_period);
/**
* bif_ctrl_get_bus_state() - get the current state of the BIF bus
* @ctrl: BIF controller consumer handle
*
* Returns a bus state from enum bif_bus_state if successful or errno if an
* error occurred.
*/
int bif_ctrl_get_bus_state(struct bif_ctrl *ctrl)
{
int rc;
if (IS_ERR_OR_NULL(ctrl)) {
pr_err("Invalid controller handle.\n");
return -ENODEV;
}
rc = ctrl->bdev->desc->ops->get_bus_state(ctrl->bdev);
if (rc < 0)
pr_err("Error during bus state retrieval, rc=%d\n", rc);
return rc;
}
EXPORT_SYMBOL(bif_ctrl_get_bus_state);
/**
* bif_ctrl_set_bus_state() - set the state of the BIF bus
* @ctrl: BIF controller consumer handle
* @state: State for the BIF bus to enter
*
* Returns 0 on success or errno if an error occurred.
*/
int bif_ctrl_set_bus_state(struct bif_ctrl *ctrl, enum bif_bus_state state)
{
int rc;
if (IS_ERR_OR_NULL(ctrl)) {
pr_err("Invalid controller handle.\n");
return -ENODEV;
}
bif_ctrl_lock(ctrl);
rc = ctrl->bdev->desc->ops->set_bus_state(ctrl->bdev, state);
if (rc < 0)
pr_err("Error during bus state configuration, rc=%d\n", rc);
/*
* Uncache the selected slave if the new bus state results in the slave
* becoming unselected.
*/
if (state == BIF_BUS_STATE_MASTER_DISABLED
|| state == BIF_BUS_STATE_POWER_DOWN
|| state == BIF_BUS_STATE_STANDBY)
ctrl->bdev->selected_sdev = NULL;
bif_ctrl_unlock(ctrl);
return rc;
}
EXPORT_SYMBOL(bif_ctrl_set_bus_state);
/*
* Check if the specified function is a protocol function and if it is, then
* instantiate protocol function data for the slave.
*/
static int bif_initialize_protocol_function(struct bif_slave_dev *sdev,
struct bif_ddb_l2_data *func)
{
int rc = 0;
u8 buf[4];
/* Ensure that this is a protocol function. */
if (func->function_type != BIF_FUNC_PROTOCOL)
return 0;
if (sdev->protocol_function) {
pr_err("Duplicate protocol function found for BIF slave; DEV_ADR=0x%02X\n",
sdev->slave_addr);
return -EPERM;
}
sdev->protocol_function = kzalloc(sizeof(struct bif_protocol_function),
GFP_KERNEL);
if (!sdev->protocol_function) {
pr_err("out of memory\n");
return -ENOMEM;
}
rc = _bif_slave_read(sdev, func->function_pointer, buf, 4);
if (rc) {
pr_err("Protocol function data read failed, rc=%d\n", rc);
return rc;
}
sdev->protocol_function->protocol_pointer = buf[0] << 8 | buf[1];
sdev->protocol_function->device_id_pointer = buf[2] << 8 | buf[3];
sdev->protocol_function->l2_entry = func;
rc = _bif_slave_read(sdev, sdev->protocol_function->device_id_pointer,
sdev->protocol_function->device_id, BIF_DEVICE_ID_BYTE_LENGTH);
if (rc) {
pr_err("Device ID read failed, rc=%d\n", rc);
return rc;
}
/* Check if this slave does not have a UID value stored. */
if (sdev->unique_id_bits_known == 0) {
sdev->unique_id_bits_known = BIF_UNIQUE_ID_BIT_LENGTH;
/* Fill in UID using manufacturer ID and device ID. */
sdev->unique_id[0] = sdev->l1_data.manufacturer_id >> 8;
sdev->unique_id[1] = sdev->l1_data.manufacturer_id;
memcpy(&sdev->unique_id[2],
sdev->protocol_function->device_id,
BIF_DEVICE_ID_BYTE_LENGTH);
}
return rc;
}
/*
* Check if the specified function is a slave control function and if it is,
* then instantiate slave control function data for the slave.
*/
static int bif_initialize_slave_control_function(struct bif_slave_dev *sdev,
struct bif_ddb_l2_data *func)
{
int rc = 0;
int i;
u8 buf[3];
/* Ensure that this is a slave control function. */
if (func->function_type != BIF_FUNC_SLAVE_CONTROL)
return 0;
if (sdev->slave_ctrl_function) {
pr_err("Duplicate slave control function found for BIF slave; DEV_ADR=0x%02X\n",
sdev->slave_addr);
return -EPERM;
}
sdev->slave_ctrl_function
= kzalloc(sizeof(struct bif_protocol_function), GFP_KERNEL);
if (!sdev->slave_ctrl_function) {
pr_err("out of memory\n");
return -ENOMEM;
}
rc = _bif_slave_read(sdev, func->function_pointer, buf, 3);
if (rc) {
pr_err("Slave control function data read failed, rc=%d\n", rc);
return rc;
}
sdev->slave_ctrl_function->slave_ctrl_pointer = buf[0] << 8 | buf[1];
sdev->slave_ctrl_function->task_count
= buf[2] * SLAVE_CTRL_TASKS_PER_SET;
sdev->slave_ctrl_function->l2_entry = func;
if (sdev->slave_ctrl_function->task_count > 0) {
sdev->slave_ctrl_function->irq_notifier_list =
kzalloc(sizeof(struct blocking_notifier_head)
* sdev->slave_ctrl_function->task_count,
GFP_KERNEL);
if (!sdev->slave_ctrl_function->irq_notifier_list) {
pr_err("out of memory\n");
kfree(sdev->slave_ctrl_function);
return -ENOMEM;
}
for (i = 0; i < sdev->slave_ctrl_function->task_count; i++) {
BLOCKING_INIT_NOTIFIER_HEAD(
&sdev->slave_ctrl_function->irq_notifier_list[i]);
}
}
return rc;
}
/*
* Check if the specified function is an NVM function and if it is, then
* instantiate NVM function data for the slave and read all objects.
*/
static int bif_initialize_nvm_function(struct bif_slave_dev *sdev,
struct bif_ddb_l2_data *func)
{
int rc = 0;
int data_len, read_size;
u8 buf[8], object_type;
struct bif_object *object;
struct bif_object *temp;
u16 addr;
u16 crc;
/* Ensure that this is an NVM function. */
if (func->function_type != BIF_FUNC_NVM)
return 0;
if (sdev->nvm_function) {
pr_err("Duplicate NVM function found for BIF slave; DEV_ADR=0x%02X\n",
sdev->slave_addr);
return -EPERM;
}
sdev->nvm_function
= kzalloc(sizeof(*sdev->nvm_function), GFP_KERNEL);
if (!sdev->nvm_function) {
pr_err("out of memory\n");
return -ENOMEM;
}
rc = _bif_slave_read(sdev, func->function_pointer, buf, 8);
if (rc) {
pr_err("NVM function data read failed, rc=%d\n", rc);
return rc;
}
sdev->nvm_function->nvm_pointer = buf[0] << 8 | buf[1];
sdev->nvm_function->slave_control_channel = buf[2];
sdev->nvm_function->write_buffer_size = buf[3];
sdev->nvm_function->nvm_base_address = buf[4] << 8 | buf[5];
sdev->nvm_function->nvm_size = buf[6] << 8 | buf[7];
/* Read NVM lock offset */
rc = _bif_slave_read(sdev, sdev->nvm_function->nvm_pointer, buf, 2);
if (rc) {
pr_err("Slave memory read failed, rc=%d\n", rc);
return rc;
}
sdev->nvm_function->nvm_lock_offset = buf[0] << 8 | buf[1];
INIT_LIST_HEAD(&sdev->nvm_function->object_list);
/* Read object list */
addr = sdev->nvm_function->nvm_base_address;
rc = _bif_slave_read(sdev, addr, &object_type, 1);
if (rc) {
pr_err("Slave memory read failed, rc=%d\n", rc);
return rc;
}
while (object_type != BIF_OBJ_END_OF_LIST) {
object = kzalloc(sizeof(*object), GFP_KERNEL);
if (!object) {
pr_err("out of memory\n");
rc = -ENOMEM;
goto free_data;
}
list_add_tail(&object->list, &sdev->nvm_function->object_list);
rc = _bif_slave_read(sdev, addr + 1, buf + 1, 5);
if (rc) {
pr_err("Slave memory read of object header failed; addr=0x%04X, len=%d, rc=%d\n",
addr + 1, 5, rc);
goto free_data;
}
object->addr = addr;
object->type = object_type;
object->version = buf[1];
object->manufacturer_id = buf[2] << 8 | buf[3];
object->length = buf[4] << 8 | buf[5];
if ((object->addr + object->length)
> (sdev->nvm_function->nvm_base_address
+ sdev->nvm_function->nvm_size)) {
pr_warn("warning: BIF slave object is not formatted correctly; NVM base=0x%04X, NVM len=%d, object addr=0x%04X, object len=%d\n",
sdev->nvm_function->nvm_base_address,
sdev->nvm_function->nvm_size,
object->addr,
object->length);
/* Limit object size to remaining NVM size. */
object->length = sdev->nvm_function->nvm_size
+ sdev->nvm_function->nvm_base_address
- object->addr;
}
/* Object header + CRC takes up 8 bytes. */
data_len = object->length - 8;
object->data = kmalloc(data_len, GFP_KERNEL);
if (!object->data) {
pr_err("out of memory\n");
rc = -ENOMEM;
goto free_data;
}
rc = _bif_slave_read(sdev, addr + 6, object->data, data_len);
if (rc) {
pr_err("Slave memory read of object data failed; addr=0x%04X, len=%d, rc=%d\n",
addr + 6, data_len, rc);
goto free_data;
}
if ((object->length + addr) >= (sdev->nvm_function->nvm_size
+ sdev->nvm_function->nvm_base_address))
read_size = 2;
else
read_size = 3;
rc = _bif_slave_read(sdev, addr + 6 + data_len, buf, read_size);
if (rc) {
pr_err("Slave memory read of object CRC failed; addr=0x%04X, len=%d, rc=%d\n",
addr + 6 + data_len, read_size, rc);
goto free_data;
}
object->crc = buf[0] << 8 | buf[1];
object_type = (read_size == 3) ? buf[2] : BIF_OBJ_END_OF_LIST;
sdev->nvm_function->object_count++;
crc = bif_object_crc_ccitt(object);
if (crc != object->crc)
pr_info("BIF object at addr=0x%04X has invalid CRC; crc calc=0x%04X, crc exp=0x%04X\n",
object->addr, crc, object->crc);
addr += object->length;
}
return rc;
free_data:
list_for_each_entry_safe(object, temp,
&sdev->nvm_function->object_list, list) {
list_del(&object->list);
kfree(object->data);
kfree(object);
}
kfree(sdev->nvm_function);
sdev->nvm_function = NULL;
return rc;
}
static int bif_parse_slave_data(struct bif_slave_dev *sdev)
{
int rc = 0;
u8 buf[10];
u8 *func_buf;
struct bif_ddb_l2_data *func;
int function_count, i;
rc = _bif_slave_read(sdev, BIF_DDB_L1_BASE_ADDR, buf, 10);
if (rc) {
pr_err("DDB L1 data read failed, rc=%d\n", rc);
return rc;
}
sdev->l1_data.revision = buf[0];
sdev->l1_data.level = buf[1];
sdev->l1_data.device_class = buf[2] << 8 | buf[3];
sdev->l1_data.manufacturer_id = buf[4] << 8 | buf[5];
sdev->l1_data.product_id = buf[6] << 8 | buf[7];
sdev->l1_data.length = buf[8] << 8 | buf[9];
function_count = sdev->l1_data.length / 4;
if (sdev->l1_data.length % 4) {
pr_err("Function directory length=%d is invalid\n",
sdev->l1_data.length);
return -EPROTO;
}
/* No DDB L2 function directory */
if (function_count == 0)
return 0;
func_buf = kmalloc(sdev->l1_data.length, GFP_KERNEL);
if (!func_buf) {
pr_err("out of memory\n");
return -ENOMEM;
}
sdev->function_directory = kzalloc(
function_count * sizeof(struct bif_ddb_l2_data), GFP_KERNEL);
if (!sdev->function_directory) {
pr_err("out of memory\n");
return -ENOMEM;
}
rc = _bif_slave_read(sdev, BIF_DDB_L2_BASE_ADDR, func_buf,
sdev->l1_data.length);
if (rc) {
pr_err("DDB L2 data read failed, rc=%d\n", rc);
return rc;
}
for (i = 0; i < function_count; i++) {
func = &sdev->function_directory[i];
func->function_type = func_buf[i * 4];
func->function_version = func_buf[i * 4 + 1];
func->function_pointer = func_buf[i * 4 + 2] << 8
| func_buf[i * 4 + 3];
rc = bif_initialize_protocol_function(sdev, func);
if (rc)
goto done;
rc = bif_initialize_slave_control_function(sdev, func);
if (rc)
goto done;
rc = bif_initialize_nvm_function(sdev, func);
if (rc)
goto done;
}
done:
kfree(func_buf);
return rc;
}
static int bif_add_secondary_slaves(struct bif_slave_dev *primary_slave)
{
int rc = 0;
int data_len, i;
u16 crc;
struct bif_slave_dev *sdev;
struct bif_object *object;
list_for_each_entry(object, &primary_slave->nvm_function->object_list,
list) {
if (object->type != BIF_OBJ_SEC_SLAVE)
continue;
data_len = object->length - 8;
if (data_len % BIF_UNIQUE_ID_BYTE_LENGTH) {
pr_info("Invalid secondary slave object found, addr=0x%04X, data len=%d\n",
object->addr, data_len);
continue;
}
crc = bif_object_crc_ccitt(object);
if (crc != object->crc) {
pr_info("BIF object at addr=0x%04X has invalid CRC; crc calc=0x%04X, crc exp=0x%04X\n",
object->addr, crc, object->crc);
continue;
}
for (i = 0; i < data_len / BIF_UNIQUE_ID_BYTE_LENGTH; i++) {
sdev = bif_add_slave(primary_slave->bdev);
if (IS_ERR(sdev)) {
rc = PTR_ERR(sdev);
pr_err("bif_add_slave failed, rc=%d\n", rc);
return rc;
}
memcpy(sdev->unique_id,
&object->data[i * BIF_UNIQUE_ID_BYTE_LENGTH],
BIF_UNIQUE_ID_BYTE_LENGTH);
sdev->unique_id_bits_known = BIF_UNIQUE_ID_BIT_LENGTH;
rc = bif_select_slave(sdev);
if (rc) {
pr_err("Could not select slave, rc=%d\n", rc);
goto free_slave;
}
rc = bif_is_slave_selected(sdev->bdev);
if (rc < 0) {
pr_err("Transaction failed, rc=%d\n", rc);
goto free_slave;
} else if (rc == 1) {
sdev->present = true;
sdev->bdev->selected_sdev = sdev;
rc = bif_parse_slave_data(sdev);
if (rc) {
pr_err("Failed to parse secondary slave data, rc=%d\n",
rc);
goto free_slave;
}
} else {
sdev->present = false;
sdev->bdev->selected_sdev = NULL;
}
}
}
return rc;
free_slave:
bif_remove_slave(sdev);
return rc;
}
/*
* Performs UID search to identify all slaves attached to the bus. Assumes that
* all necessary locks are held.
*/
static int bif_perform_uid_search(struct bif_ctrl_dev *bdev)
{
struct bif_slave_dev *sdev;
struct bif_slave_dev *new_slave;
bool resp[2], resp_dilc;
int i;
int rc = 0;
u8 cmd_probe[2] = {BIF_CMD_DIP0, BIF_CMD_DIP1};
u8 cmd_enter[2] = {BIF_CMD_DIE0, BIF_CMD_DIE1};
/*
* Iterate over all partially known UIDs adding new ones as they are
* found.
*/
list_for_each_entry(sdev, &bif_sdev_list, list) {
/* Skip slaves with fully known UIDs. */
if (sdev->unique_id_bits_known == BIF_UNIQUE_ID_BIT_LENGTH
|| sdev->bdev != bdev)
continue;
/* Begin a new UID search. */
rc = bdev->desc->ops->bus_transaction(bdev, BIF_TRANS_BC,
BIF_CMD_DISS);
if (rc) {
pr_err("bus_transaction failed, rc=%d\n", rc);
return rc;
}
/* Step through all known UID bits (MSB to LSB). */
for (i = 0; i < sdev->unique_id_bits_known; i++) {
rc = bdev->desc->ops->bus_transaction(bdev,
BIF_TRANS_BC,
cmd_enter[get_uid_bit(sdev->unique_id, i)]);
if (rc) {
pr_err("bus_transaction failed, rc=%d\n", rc);
return rc;
}
}
/* Step through unknown UID bits. */
for (i = sdev->unique_id_bits_known;
i < BIF_UNIQUE_ID_BIT_LENGTH; i++) {
rc = bdev->desc->ops->bus_transaction_query(bdev,
BIF_TRANS_BC, cmd_probe[0], &resp[0]);
if (rc) {
pr_err("bus_transaction failed, rc=%d\n", rc);
return rc;
}
rc = bdev->desc->ops->bus_transaction_query(bdev,
BIF_TRANS_BC, cmd_probe[1], &resp[1]);
if (rc) {
pr_err("bus_transaction failed, rc=%d\n", rc);
return rc;
}
if (resp[0] && resp[1]) {
/* Create an entry for the new UID branch. */
new_slave = bif_add_slave(bdev);
if (IS_ERR(new_slave)) {
rc = PTR_ERR(sdev);
pr_err("bif_add_slave failed, rc=%d\n",
rc);
return rc;
}
memcpy(new_slave->unique_id, sdev->unique_id,
BIF_UNIQUE_ID_BYTE_LENGTH);
new_slave->bdev = sdev->bdev;
set_uid_bit(sdev->unique_id, i, 0);
sdev->unique_id_bits_known = i + 1;
set_uid_bit(new_slave->unique_id, i, 1);
new_slave->unique_id_bits_known = i + 1;
} else if (resp[0]) {
set_uid_bit(sdev->unique_id, i, 0);
sdev->unique_id_bits_known = i + 1;
} else if (resp[1]) {
set_uid_bit(sdev->unique_id, i, 1);
sdev->unique_id_bits_known = i + 1;
} else {
pr_debug("no bus query response received\n");
rc = -ENXIO;
return rc;
}
rc = bdev->desc->ops->bus_transaction(bdev,
BIF_TRANS_BC, cmd_enter[resp[0] ? 0 : 1]);
if (rc) {
pr_err("bus_transaction failed, rc=%d\n", rc);
return rc;
}
}
rc = bdev->desc->ops->bus_transaction_query(bdev,
BIF_TRANS_BC, BIF_CMD_DILC, &resp_dilc);
if (rc) {
pr_err("bus_transaction failed, rc=%d\n", rc);
return rc;
}
if (resp_dilc) {
sdev->present = true;
sdev->bdev->selected_sdev = sdev;
rc = bif_parse_slave_data(sdev);
if (rc) {
pr_err("Failed to parse secondary slave data, rc=%d\n",
rc);
return rc;
}
} else {
pr_err("Slave failed to respond to DILC bus command; its UID is thus unverified.\n");
sdev->unique_id_bits_known = 0;
rc = -ENXIO;
return rc;
}
}
return rc;
}
/*
* Removes slaves from the bif_sdev_list which have the same UID as previous
* slaves in the list.
*/
static int bif_remove_duplicate_slaves(struct bif_ctrl_dev *bdev)
{
struct bif_slave_dev *sdev;
struct bif_slave_dev *last_slave;
struct bif_slave_dev *temp;
list_for_each_entry_safe(last_slave, temp, &bif_sdev_list, list) {
list_for_each_entry(sdev, &bif_sdev_list, list) {
if (last_slave == sdev) {
break;
} else if (memcmp(last_slave->unique_id,
sdev->unique_id,
BIF_UNIQUE_ID_BYTE_LENGTH) == 0) {
bif_remove_slave(last_slave);
break;
}
}
}
return 0;
}
static int bif_add_all_slaves(struct bif_ctrl_dev *bdev)
{
struct bif_slave_dev *sdev;
int rc = 0;
int i;
bool has_slave = false, is_primary_slave = false;
mutex_lock(&bif_sdev_list_mutex);
mutex_lock(&bdev->mutex);
list_for_each_entry(sdev, &bif_sdev_list, list) {
if (sdev->bdev == bdev) {
has_slave = true;
break;
}
}
if (!has_slave) {
/* Create a single empty slave to start the search algorithm. */
sdev = bif_add_slave(bdev);
if (IS_ERR(sdev)) {
rc = PTR_ERR(sdev);
pr_err("bif_add_slave failed, rc=%d\n", rc);
goto out;
}
for (i = 0; i < BIF_TRANSACTION_RETRY_COUNT; i++) {
/* Attempt to select primary slave in battery pack. */
rc = bdev->desc->ops->bus_transaction(bdev,
BIF_TRANS_SDA, BIF_PRIMARY_SLAVE_DEV_ADR);
if (rc == 0)
break;
}
if (rc) {
pr_err("BIF bus_transaction failed, rc=%d\n", rc);
goto out;
}
/* Check if a slave is selected. */
rc = bif_is_slave_selected(bdev);
if (rc < 0) {
pr_err("BIF bus_transaction failed, rc=%d\n", rc);
goto out;
} else {
is_primary_slave = rc;
}
}
if (is_primary_slave) {
pr_debug("Using primary slave at DEV_ADR==0x%02X\n",
BIF_PRIMARY_SLAVE_DEV_ADR);
sdev->bdev->selected_sdev = sdev;
sdev->present = true;
sdev->slave_addr = BIF_PRIMARY_SLAVE_DEV_ADR;
rc = bif_parse_slave_data(sdev);
if (rc) {
pr_err("Failed to parse primary slave data, rc=%d\n",
rc);
goto out;
}
rc = bif_add_secondary_slaves(sdev);
if (rc) {
pr_err("Failed to add secondary slaves, rc=%d\n", rc);
goto out;
}
} else {
pr_debug("Falling back on full UID search.\n");
for (i = 0; i < BIF_TRANSACTION_RETRY_COUNT; i++) {
rc = bif_perform_uid_search(bdev);
if (rc == 0)
break;
}
if (rc) {
pr_debug("BIF UID search failed, rc=%d\n", rc);
goto out;
}
}
bif_remove_duplicate_slaves(bdev);
mutex_unlock(&bdev->mutex);
mutex_unlock(&bif_sdev_list_mutex);
return rc;
out:
mutex_unlock(&bdev->mutex);
mutex_unlock(&bif_sdev_list_mutex);
pr_debug("BIF slave search failed, rc=%d\n", rc);
return rc;
}
static int bif_add_known_slave(struct bif_ctrl_dev *bdev, u8 slave_addr)
{
struct bif_slave_dev *sdev;
int rc = 0;
int i;
for (i = 0; i < BIF_TRANSACTION_RETRY_COUNT; i++) {
/* Attempt to select the slave. */
rc = bdev->desc->ops->bus_transaction(bdev, BIF_TRANS_SDA,
slave_addr);
if (rc == 0)
break;
}
if (rc) {
pr_err("BIF bus_transaction failed, rc=%d\n", rc);
return rc;
}
/* Check if a slave is selected. */
rc = bif_is_slave_selected(bdev);
if (rc < 0) {
pr_err("BIF bus_transaction failed, rc=%d\n", rc);
return rc;
}
sdev = bif_add_slave(bdev);
if (IS_ERR(sdev)) {
rc = PTR_ERR(sdev);
pr_err("bif_add_slave failed, rc=%d\n", rc);
return rc;
}
sdev->bdev->selected_sdev = sdev;
sdev->present = true;
sdev->slave_addr = slave_addr;
rc = bif_parse_slave_data(sdev);
if (rc) {
pr_err("Failed to parse slave data, addr=0x%02X, rc=%d\n",
slave_addr, rc);
return rc;
}
return rc;
}
static int bif_add_known_slaves_from_dt(struct bif_ctrl_dev *bdev,
struct device_node *of_node)
{
int len = 0;
int rc, i;
u32 addr;
const __be32 *val;
mutex_lock(&bif_sdev_list_mutex);
mutex_lock(&bdev->mutex);
val = of_get_property(of_node, "qcom,known-device-addresses", &len);
len /= sizeof(u32);
if (val && len == 0) {
pr_err("qcom,known-device-addresses property is invalid\n");
rc = -EINVAL;
goto out;
}
for (i = 0; i < len; i++) {
addr = be32_to_cpup(val++);
if (addr == 0x00 || addr > 0xFF) {
rc = -EINVAL;
pr_err("qcom,known-device-addresses property contains invalid address=0x%X\n",
addr);
goto out;
}
rc = bif_add_known_slave(bdev, addr);
if (rc) {
pr_err("bif_add_known_slave() failed, rc=%d\n", rc);
goto out;
}
}
out:
if (len > 0)
bif_remove_duplicate_slaves(bdev);
mutex_unlock(&bdev->mutex);
mutex_unlock(&bif_sdev_list_mutex);
return rc;
}
/*
* Programs a device address for the specified slave in order to simplify
* slave selection in the future.
*/
static int bif_assign_slave_dev_addr(struct bif_slave_dev *sdev, u8 dev_addr)
{
int rc;
u16 addr;
if (!sdev->protocol_function) {
pr_err("Protocol function not present; cannot set device address.\n");
return -ENODEV;
}
addr = PROTOCOL_FUNC_DEV_ADR_ADDR(
sdev->protocol_function->protocol_pointer);
rc = _bif_slave_write(sdev, addr, &dev_addr, 1);
if (rc)
pr_err("Failed to set slave device address.\n");
else
sdev->slave_addr = dev_addr;
return rc;
}
/* Assigns a unique device address to all slaves which do not have one. */
static int bif_assign_all_slaves_dev_addr(struct bif_ctrl_dev *bdev)
{
struct bif_slave_dev *sdev;
struct bif_slave_dev *sibling;
bool duplicate;
int rc = 0;
u8 dev_addr, first_dev_addr;
mutex_lock(&bif_sdev_list_mutex);
mutex_lock(&bdev->mutex);
first_dev_addr = next_dev_addr;
/*
* Iterate over all partially known UIDs adding new ones as they are
* found.
*/
list_for_each_entry(sdev, &bif_sdev_list, list) {
/*
* Skip slaves without known UIDs, which already have a device
* address or which aren't present.
*/
if (sdev->unique_id_bits_known != BIF_UNIQUE_ID_BIT_LENGTH
|| sdev->slave_addr != 0x00 || !sdev->present)
continue;
do {
dev_addr = next_dev_addr;
duplicate = false;
list_for_each_entry(sibling, &bif_sdev_list, list) {
if (sibling->slave_addr == dev_addr) {
duplicate = true;
break;
}
}
next_dev_addr = dev_addr + 1;
} while (duplicate && (next_dev_addr != first_dev_addr));
if (next_dev_addr == first_dev_addr) {
pr_err("No more BIF slave device addresses available.\n");
rc = -ENODEV;
goto out;
}
rc = bif_assign_slave_dev_addr(sdev, dev_addr);
if (rc) {
pr_err("Failed to set slave address.\n");
goto out;
}
}
mutex_unlock(&bdev->mutex);
mutex_unlock(&bif_sdev_list_mutex);
return rc;
out:
mutex_unlock(&bdev->mutex);
mutex_unlock(&bif_sdev_list_mutex);
pr_err("BIF slave device address setting failed, rc=%d\n", rc);
return rc;
}
/**
* bdev_get_drvdata() - get the private BIF controller driver data
* @bdev: BIF controller device pointer
*/
void *bdev_get_drvdata(struct bif_ctrl_dev *bdev)
{
return bdev->driver_data;
}
EXPORT_SYMBOL(bdev_get_drvdata);
static const char * const battery_label[] = {
"unknown",
"none",
"special 1",
"special 2",
"special 3",
"low cost",
"smart",
};
static const char *bif_get_battery_pack_type(int rid_ohm)
{
const char *label = battery_label[0];
if (rid_ohm > BIF_BATT_RID_SMART_MAX)
label = battery_label[1];
else if (rid_ohm >= BIF_BATT_RID_SMART_MIN)
label = battery_label[6];
else if (rid_ohm >= BIF_BATT_RID_LOW_COST_MIN
&& rid_ohm <= BIF_BATT_RID_LOW_COST_MAX)
label = battery_label[5];
else if (rid_ohm >= BIF_BATT_RID_SPECIAL3_MIN
&& rid_ohm <= BIF_BATT_RID_SPECIAL3_MAX)
label = battery_label[4];
else if (rid_ohm >= BIF_BATT_RID_SPECIAL2_MIN
&& rid_ohm <= BIF_BATT_RID_SPECIAL2_MAX)
label = battery_label[3];
else if (rid_ohm >= BIF_BATT_RID_SPECIAL1_MIN
&& rid_ohm <= BIF_BATT_RID_SPECIAL1_MAX)
label = battery_label[2];
return label;
}
/**
* bif_ctrl_register() - register a BIF controller with the BIF framework
* @bif_desc: Pointer to BIF controller descriptor
* @dev: Device pointer of the BIF controller
* @driver_data: Private driver data to associate with the BIF controller
* @of_node Pointer to the device tree node of the BIF controller
*
* Returns a BIF controller device pointer for the controller if registration
* is successful or an ERR_PTR if an error occurred.
*/
struct bif_ctrl_dev *bif_ctrl_register(struct bif_ctrl_desc *bif_desc,
struct device *dev, void *driver_data, struct device_node *of_node)
{
struct bif_ctrl_dev *bdev = ERR_PTR(-EINVAL);
struct bif_slave_dev *sdev;
bool battery_present = false;
bool slaves_present = false;
int rc, rid_ohm;
if (!bif_desc) {
pr_err("Invalid bif_desc specified\n");
return bdev;
} else if (!bif_desc->name) {
pr_err("BIF name missing\n");
return bdev;
} else if (!bif_desc->ops) {
pr_err("BIF operations missing\n");
return bdev;
} else if (!bif_desc->ops->bus_transaction
|| !bif_desc->ops->bus_transaction_query
|| !bif_desc->ops->bus_transaction_read
|| !bif_desc->ops->get_bus_state
|| !bif_desc->ops->set_bus_state) {
pr_err("BIF operation callback function(s) missing\n");
return bdev;
}
bdev = kzalloc(sizeof(struct bif_ctrl_dev), GFP_KERNEL);
if (bdev == NULL) {
pr_err("Memory allocation failed for bif_ctrl_dev\n");
return ERR_PTR(-ENOMEM);
}
mutex_init(&bdev->mutex);
INIT_LIST_HEAD(&bdev->list);
INIT_DELAYED_WORK(&bdev->enter_irq_mode_work, bif_enter_irq_mode_work);
bdev->desc = bif_desc;
bdev->ctrl_dev = dev;
bdev->driver_data = driver_data;
bdev->irq_mode_delay_jiffies = 2;
mutex_lock(&bif_ctrl_list_mutex);
list_add_tail(&bdev->list, &bif_ctrl_list);
mutex_unlock(&bif_ctrl_list_mutex);
rc = bif_add_all_slaves(bdev);
if (rc)
pr_debug("Search for all slaves failed, rc=%d\n", rc);
rc = bif_add_known_slaves_from_dt(bdev, of_node);
if (rc)
pr_err("Adding slaves based on device tree addressed failed, rc=%d.\n",
rc);
rc = bif_assign_all_slaves_dev_addr(bdev);
if (rc)
pr_err("Failed to set slave device address, rc=%d\n", rc);
bif_print_slaves();
if (bdev->desc->ops->get_battery_presence) {
rc = bdev->desc->ops->get_battery_presence(bdev);
if (rc < 0) {
pr_err("Could not determine battery presence, rc=%d\n",
rc);
} else {
battery_present = rc;
pr_info("Battery pack present = %c\n", rc ? 'Y' : 'N');
}
}
if (bdev->desc->ops->get_battery_rid) {
rid_ohm = bdev->desc->ops->get_battery_rid(bdev);
if (rid_ohm >= 0)
pr_info("Battery pack type = %s (Rid=%d ohm)\n",
bif_get_battery_pack_type(rid_ohm), rid_ohm);
else
pr_err("Could not read Rid, rc=%d\n", rid_ohm);
}
list_for_each_entry(sdev, &bif_sdev_list, list) {
if (sdev->present) {
battery_present = true;
slaves_present = true;
break;
}
}
BLOCKING_INIT_NOTIFIER_HEAD(&bdev->bus_change_notifier);
/* Disable the BIF bus master if no slaves are found. */
if (!slaves_present) {
rc = bdev->desc->ops->set_bus_state(bdev,
BIF_BUS_STATE_MASTER_DISABLED);
if (rc < 0)
pr_err("Could not disble BIF master, rc=%d\n", rc);
}
if (battery_present) {
bdev->battery_present = true;
rc = blocking_notifier_call_chain(&bdev->bus_change_notifier,
BIF_BUS_EVENT_BATTERY_INSERTED, bdev);
if (rc)
pr_err("Call chain noification failed, rc=%d\n", rc);
}
return bdev;
}
EXPORT_SYMBOL(bif_ctrl_register);
/**
* bif_ctrl_unregister() - unregisters a BIF controller
* @bdev: BIF controller device pointer
*/
void bif_ctrl_unregister(struct bif_ctrl_dev *bdev)
{
if (bdev) {
mutex_lock(&bif_ctrl_list_mutex);
list_del(&bdev->list);
mutex_unlock(&bif_ctrl_list_mutex);
}
}
EXPORT_SYMBOL(bif_ctrl_unregister);