kernel_samsung_a34x-permissive/sound/soc/codecs/dbmdx/dbmdx-i2c.c
2024-04-28 15:49:01 +02:00

922 lines
22 KiB
C
Executable file

/*
* DSPG DBMDX I2C interface driver
*
* Copyright (C) 2014 DSP Group
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 DEBUG */
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#if IS_ENABLED(CONFIG_OF)
#include <linux/of.h>
#include <linux/of_gpio.h>
#endif
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/clk.h>
#include <linux/firmware.h>
#include "dbmdx-interface.h"
#include "dbmdx-va-regmap.h"
#include "dbmdx-vqe-regmap.h"
#include "dbmdx-i2c.h"
#define DEFAULT_I2C_WRITE_CHUNK_SIZE 32
#define MAX_I2C_WRITE_CHUNK_SIZE 128
#define DEFAULT_I2C_READ_CHUNK_SIZE 8
#define MAX_I2C_READ_CHUNK_SIZE 128
static DECLARE_WAIT_QUEUE_HEAD(dbmdx_wq);
ssize_t send_i2c_cmd_vqe(struct dbmdx_private *p,
u32 command, u16 *response)
{
struct dbmdx_i2c_private *i2c_p =
(struct dbmdx_i2c_private *)p->chip->pdata;
u8 send[4];
u8 recv[4];
ssize_t ret = 0;
int retries = 10;
send[0] = (command >> 24) & 0xff;
send[1] = (command >> 16) & 0xff;
send[2] = (command >> 8) & 0xff;
send[3] = command & 0xff;
ret = i2c_master_send(i2c_p->client, send, 4);
if (ret < 0) {
dev_err(i2c_p->dev,
"%s: cmd:0x%08X - i2c_master_send failed ret:%zd\n",
__func__, command, ret);
return ret;
}
usleep_range(DBMDX_USLEEP_I2C_VQE_CMD_AFTER_SEND,
DBMDX_USLEEP_I2C_VQE_CMD_AFTER_SEND + 1000);
if ((command == (DBMDX_VQE_SET_POWER_STATE_CMD |
DBMDX_VQE_SET_POWER_STATE_HIBERNATE)) ||
(command == DBMDX_VQE_SET_SWITCH_TO_BOOT_CMD))
return 0;
/* we need additional sleep till system is ready */
if (command == (DBMDX_VQE_SET_SYSTEM_CONFIG_CMD |
DBMDX_VQE_SET_SYSTEM_CONFIG_PRIMARY_CFG))
msleep(DBMDX_MSLEEP_I2C_VQE_SYS_CFG_CMD);
/* read response */
do {
ret = i2c_master_recv(i2c_p->client, recv, 4);
if (ret < 0) {
/* Wait before polling again */
usleep_range(10000, 11000);
continue;
}
/*
* Check that the first two bytes of the response match
* (the ack is in those bytes)
*/
if ((send[0] == recv[0]) && (send[1] == recv[1])) {
if (response)
*response = (recv[2] << 8) | recv[3];
ret = 0;
break;
}
dev_warn(i2c_p->dev,
"%s: incorrect ack (got 0x%.2x%.2x)\n",
__func__, recv[0], recv[1]);
ret = -EINVAL;
/* Wait before polling again */
usleep_range(10000, 11000);
} while (--retries);
if (!retries)
dev_err(i2c_p->dev,
"%s: cmd:0x%8x - wrong ack, giving up\n",
__func__, command);
return ret;
}
ssize_t send_i2c_cmd_va(struct dbmdx_private *p, u32 command,
u16 *response)
{
struct dbmdx_i2c_private *i2c_p =
(struct dbmdx_i2c_private *)p->chip->pdata;
u8 send[3];
u8 recv[2];
int ret;
send[0] = (command >> 16) & 0xff;
send[1] = (command >> 8) & 0xff;
send[2] = (command) & 0xff;
dev_dbg(i2c_p->dev, "%s: Send 0x%02x\n", __func__, command);
if (response) {
ret = i2c_master_send(i2c_p->client, send, 1);
if (ret < 0) {
dev_err(i2c_p->dev,
"%s: i2c_master_send failed ret = %d\n",
__func__, ret);
return ret;
}
usleep_range(DBMDX_USLEEP_I2C_VA_CMD_AFTER_SEND,
DBMDX_USLEEP_I2C_VA_CMD_AFTER_SEND + 1000);
if (p->va_debug_mode)
msleep(DBMDX_MSLEEP_DBG_MODE_CMD_RX);
ret = i2c_master_recv(i2c_p->client, recv, 2);
if (ret < 0) {
dev_err(i2c_p->dev, "%s: i2c_master_recv failed\n",
__func__);
return ret;
}
*response = (recv[0] << 8) | recv[1];
dev_dbg(i2c_p->dev, "%s: Received 0x%02x\n", __func__,
*response);
ret = 0;
} else {
ret = i2c_master_send(i2c_p->client, send, 3);
if (ret < 0) {
dev_err(i2c_p->dev,
"%s: i2c_master_send failed ret = %d\n",
__func__, ret);
return ret;
}
ret = 0;
}
usleep_range(DBMDX_USLEEP_I2C_VA_CMD_AFTER_SEND_2,
DBMDX_USLEEP_I2C_VA_CMD_AFTER_SEND_2 + 1000);
if (p->va_debug_mode)
msleep(DBMDX_MSLEEP_DBG_MODE_CMD_TX);
return ret;
}
ssize_t read_i2c_data(struct dbmdx_private *p, void *buf, size_t len)
{
struct dbmdx_i2c_private *i2c_p =
(struct dbmdx_i2c_private *)p->chip->pdata;
size_t count = i2c_p->pdata->read_chunk_size;
ssize_t i;
int ret;
u8 *d = (u8 *)buf;
/* if stuck for more than 10s, something is wrong */
unsigned long timeout = jiffies + msecs_to_jiffies(10000);
/* We are going to read everything in on chunk */
if (len < count) {
ret = i2c_master_recv(i2c_p->client, buf, len);
if (ret < 0) {
dev_err(i2c_p->dev, "%s: i2c_master_recv failed\n",
__func__);
i = -EIO;
goto out;
}
return len;
}
for (i = 0; i < len; i += count) {
if ((i + count) > len)
count = len - i;
ret = i2c_master_recv(i2c_p->client,
i2c_p->pdata->read_buf, count);
if (ret < 0) {
dev_err(i2c_p->dev, "%s: i2c_master_recv failed\n",
__func__);
i = -EIO;
goto out;
}
memcpy(d + i, i2c_p->pdata->read_buf, count);
if (!time_before(jiffies, timeout)) {
dev_err(i2c_p->dev,
"%s: read data timed out after %zd bytes\n",
__func__, i);
i = -ETIMEDOUT;
goto out;
}
}
return len;
out:
return i;
}
ssize_t write_i2c_data(struct dbmdx_private *p, const void *buf,
size_t len)
{
struct dbmdx_i2c_private *i2c_p =
(struct dbmdx_i2c_private *)p->chip->pdata;
ssize_t ret = 0;
const u8 *cmds = (const u8 *)buf;
size_t to_copy = len;
size_t max_size = (size_t)(i2c_p->pdata->write_chunk_size);
while (to_copy > 0) {
ret = i2c_master_send(i2c_p->client, cmds,
min_t(size_t, to_copy, max_size));
if (ret < 0) {
dev_err(i2c_p->dev,
"%s: i2c_master_send failed ret=%zd\n",
__func__, ret);
break;
}
to_copy -= ret;
cmds += ret;
}
return len - to_copy;
}
int send_i2c_cmd_boot(struct dbmdx_private *p, u32 command)
{
struct dbmdx_i2c_private *i2c_p =
(struct dbmdx_i2c_private *)p->chip->pdata;
u8 send[3];
int ret = 0;
dev_info(i2c_p->dev, "%s: command = %x\n", __func__, command);
send[0] = (command >> 16) & 0xff;
send[1] = (command >> 8) & 0xff;
ret = i2c_master_send(i2c_p->client, send, 2);
if (ret < 0) {
dev_err(i2c_p->dev, "%s: Failed ret = %d\n",
__func__, ret);
return ret;
}
/* A host command received will blocked until the current audio frame
* processing is finished, which can take up to 10 ms
*/
usleep_range(DBMDX_USLEEP_I2C_AFTER_BOOT_CMD,
DBMDX_USLEEP_I2C_AFTER_BOOT_CMD + 1000);
return 0;
}
int i2c_verify_boot_checksum(struct dbmdx_private *p,
const void *checksum, size_t chksum_len)
{
struct dbmdx_i2c_private *i2c_p =
(struct dbmdx_i2c_private *)p->chip->pdata;
int ret;
u8 rx_checksum[10];
if (!checksum)
return 0;
if (chksum_len > 8) {
dev_err(i2c_p->dev, "%s: illegal checksum length\n", __func__);
return -EINVAL;
}
ret = send_i2c_cmd_boot(p, DBMDX_READ_CHECKSUM);
if (ret < 0) {
dev_err(i2c_p->dev, "%s: could not read checksum\n", __func__);
return -EIO;
}
ret = i2c_master_recv(i2c_p->client, (void *)rx_checksum,
chksum_len + 2);
if (ret < 0) {
dev_err(i2c_p->dev, "%s: could not read checksum data\n",
__func__);
return -EIO;
}
ret = p->verify_checksum(p, checksum, &rx_checksum[2], chksum_len);
if (ret) {
dev_err(i2c_p->dev, "%s: checksum mismatch\n", __func__);
return -EILSEQ;
}
return 0;
}
int i2c_verify_chip_id(struct dbmdx_private *p)
{
struct dbmdx_i2c_private *i2c_p =
(struct dbmdx_i2c_private *)p->chip->pdata;
int ret;
u8 idr_read_cmd[] = {0x5A, 0x07, 0x68, 0x00, 0x00, 0x03};
u8 idr_read_result[7] = {0};
u8 chip_rev_id_low_a = 0;
u8 chip_rev_id_low_b = 0;
u8 chip_rev_id_high = 0;
u8 recv_chip_rev_id_high = 0;
u8 recv_chip_rev_id_low = 0;
if (p->cur_firmware_id == DBMDX_FIRMWARE_ID_DBMD2) {
idr_read_cmd[2] = 0x68;
chip_rev_id_high = 0x0d;
chip_rev_id_low_a = 0xb0;
chip_rev_id_low_b = 0xb1;
} else if (p->cur_firmware_id == DBMDX_FIRMWARE_ID_DBMD4) {
idr_read_cmd[2] = 0x74;
chip_rev_id_high = 0xdb;
chip_rev_id_low_a = 0x40;
chip_rev_id_low_b = 0x40;
} else if (p->cur_firmware_id == DBMDX_FIRMWARE_ID_DBMD6) {
idr_read_cmd[2] = 0x74;
chip_rev_id_high = 0xdb;
chip_rev_id_low_a = 0x60;
chip_rev_id_low_b = 0x60;
} else {
idr_read_cmd[2] = 0x74;
chip_rev_id_high = 0xdb;
chip_rev_id_low_a = 0x80;
chip_rev_id_low_b = 0x80;
}
ret = write_i2c_data(p, idr_read_cmd, 6);
if (ret != sizeof(idr_read_cmd)) {
dev_err(i2c_p->dev, "%s: idr_read_cmd ret = %d\n",
__func__, ret);
return ret;
}
usleep_range(DBMDX_USLEEP_I2C_AFTER_BOOT_CMD,
DBMDX_USLEEP_I2C_AFTER_BOOT_CMD + 1000);
ret = i2c_master_recv(i2c_p->client, (void *)idr_read_result, 6);
if (ret < 0) {
dev_err(i2c_p->dev, "%s: could not idr register data\n",
__func__);
return -EIO;
}
/* Verify answer */
if ((idr_read_result[0] != idr_read_cmd[0]) ||
(idr_read_result[1] != idr_read_cmd[1]) ||
(idr_read_result[4] != 0x00) ||
(idr_read_result[5] != 0x00)) {
dev_err(i2c_p->dev, "%s: Wrong IDR resp: %x:%x:%x:%x:%x:%x\n",
__func__,
idr_read_result[0],
idr_read_result[1],
idr_read_result[2],
idr_read_result[3],
idr_read_result[4],
idr_read_result[5]);
return -EIO;
}
recv_chip_rev_id_high = idr_read_result[3];
recv_chip_rev_id_low = idr_read_result[2];
if ((recv_chip_rev_id_high != chip_rev_id_high) ||
((recv_chip_rev_id_low != chip_rev_id_low_a) &&
(recv_chip_rev_id_low != chip_rev_id_low_b))) {
dev_err(i2c_p->dev,
"%s: Wrong chip ID: Received 0x%2x%2x Expected: 0x%2x%2x | 0x%2x%2x\n",
__func__,
recv_chip_rev_id_high,
recv_chip_rev_id_low,
chip_rev_id_high,
chip_rev_id_low_a,
chip_rev_id_high,
chip_rev_id_low_b);
return -EILSEQ;
}
dev_info(i2c_p->dev,
"%s: Chip ID was successfully verified: 0x%2x%2x\n",
__func__,
recv_chip_rev_id_high,
recv_chip_rev_id_low);
return 0;
}
static int i2c_can_boot(struct dbmdx_private *p)
{
struct dbmdx_i2c_private *i2c_p =
(struct dbmdx_i2c_private *)p->chip->pdata;
dev_dbg(i2c_p->dev, "%s\n", __func__);
return 0;
}
static int i2c_prepare_boot(struct dbmdx_private *p)
{
struct dbmdx_i2c_private *i2c_p =
(struct dbmdx_i2c_private *)p->chip->pdata;
dev_dbg(i2c_p->dev, "%s\n", __func__);
return 0;
}
static int i2c_finish_boot(struct dbmdx_private *p)
{
struct dbmdx_i2c_private *i2c_p =
(struct dbmdx_i2c_private *)p->chip->pdata;
/* XXX */
msleep(DBMDX_MSLEEP_I2C_FINISH_BOOT);
/* change to normal operation I2C address */
i2c_p->client->addr = (unsigned short)(i2c_p->pdata->operation_addr);
i2c_set_clientdata(i2c_p->client, &p->chip);
dev_dbg(i2c_p->dev, "%s\n", __func__);
return 0;
}
static int i2c_dump_state(struct chip_interface *chip, char *buf)
{
struct dbmdx_i2c_private *i2c_p =
(struct dbmdx_i2c_private *)chip->pdata;
int off = 0;
dev_dbg(i2c_p->dev, "%s\n", __func__);
off += snprintf(buf + off, PAGE_SIZE - off,
"\t===I2C Interface Dump====\n");
off += snprintf(buf + off, PAGE_SIZE - off,
"\tI2C Write Chunk Size:\t\t%d\n",
i2c_p->pdata->write_chunk_size);
off += snprintf(buf + off, PAGE_SIZE - off,
"\tI2C Read Chunk Size:\t\t%d\n",
i2c_p->pdata->read_chunk_size);
off += snprintf(buf + off, PAGE_SIZE - off,
"\tInterface resumed:\t%s\n",
i2c_p->interface_enabled ? "ON" : "OFF");
return off;
}
static int i2c_set_va_firmware_ready(struct dbmdx_private *p)
{
struct dbmdx_i2c_private *i2c_p =
(struct dbmdx_i2c_private *)p->chip->pdata;
dev_dbg(i2c_p->dev, "%s\n", __func__);
return 0;
}
static int i2c_set_vqe_firmware_ready(struct dbmdx_private *p)
{
struct dbmdx_i2c_private *i2c_p =
(struct dbmdx_i2c_private *)p->chip->pdata;
dev_dbg(i2c_p->dev, "%s\n", __func__);
return 0;
}
static void i2c_transport_enable(struct dbmdx_private *p, bool enable)
{
struct dbmdx_i2c_private *i2c_p =
(struct dbmdx_i2c_private *)p->chip->pdata;
int ret = 0;
dev_dbg(i2c_p->dev, "%s (%s)\n", __func__, enable ? "ON" : "OFF");
if (enable) {
#if IS_ENABLED(CONFIG_PM_WAKELOCKS)
if (i2c_p->ps_nosuspend_wl)
__pm_stay_awake(i2c_p->ps_nosuspend_wl);
#endif
ret = wait_event_interruptible(dbmdx_wq,
i2c_p->interface_enabled);
if (ret)
dev_dbg(i2c_p->dev,
"%s, waiting for interface was interrupted",
__func__);
else
dev_dbg(i2c_p->dev, "%s, interface is active\n",
__func__);
}
if (enable) {
p->wakeup_set(p);
msleep(DBMDX_MSLEEP_I2C_WAKEUP);
} else {
#if IS_ENABLED(CONFIG_PM_WAKELOCKS)
if (i2c_p->ps_nosuspend_wl)
__pm_relax(i2c_p->ps_nosuspend_wl);
#endif
p->wakeup_release(p);
}
}
static void i2c_resume(struct dbmdx_private *p)
{
struct dbmdx_i2c_private *i2c_p =
(struct dbmdx_i2c_private *)p->chip->pdata;
dev_dbg(i2c_p->dev, "%s\n", __func__);
i2c_interface_resume(i2c_p);
}
void i2c_interface_resume(struct dbmdx_i2c_private *i2c_p)
{
dev_dbg(i2c_p->dev, "%s\n", __func__);
i2c_p->interface_enabled = 1;
wake_up_interruptible(&dbmdx_wq);
}
static void i2c_suspend(struct dbmdx_private *p)
{
struct dbmdx_i2c_private *i2c_p =
(struct dbmdx_i2c_private *)p->chip->pdata;
dev_dbg(i2c_p->dev, "%s\n", __func__);
i2c_interface_suspend(i2c_p);
}
void i2c_interface_suspend(struct dbmdx_i2c_private *i2c_p)
{
dev_dbg(i2c_p->dev, "%s\n", __func__);
i2c_p->interface_enabled = 0;
}
static int i2c_prepare_buffering(struct dbmdx_private *p)
{
struct dbmdx_i2c_private *i2c_p =
(struct dbmdx_i2c_private *)p->chip->pdata;
dev_dbg(i2c_p->dev, "%s\n", __func__);
return 0;
}
int i2c_read_audio_data(struct dbmdx_private *p,
void *buf,
size_t samples,
bool to_read_metadata,
size_t *available_samples,
size_t *data_offset)
{
size_t bytes_to_read;
int ret;
struct dbmdx_i2c_private *i2c_p =
(struct dbmdx_i2c_private *)p->chip->pdata;
dev_dbg(i2c_p->dev, "%s\n", __func__);
ret = send_i2c_cmd_va(p, DBMDX_VA_READ_AUDIO_BUFFER | samples, NULL);
if (ret) {
dev_err(p->dev, "%s: failed to request %zu audio samples\n",
__func__, samples);
ret = -1;
goto out;
}
*available_samples = 0;
if (to_read_metadata)
*data_offset = 8;
else
*data_offset = 0;
bytes_to_read = samples * 8 * p->bytes_per_sample + *data_offset;
ret = read_i2c_data(p, buf, bytes_to_read);
if (ret != bytes_to_read) {
dev_err(p->dev,
"%s: read audio failed, %zu bytes to read, res(%d)\n",
__func__,
bytes_to_read,
ret);
ret = -1;
goto out;
}
/* Word #4 contains current number of available samples */
if (to_read_metadata)
*available_samples = (size_t)(((u16 *)buf)[3]);
else
*available_samples = samples;
ret = samples;
out:
return ret;
}
static int i2c_finish_buffering(struct dbmdx_private *p)
{
struct dbmdx_i2c_private *i2c_p =
(struct dbmdx_i2c_private *)p->chip->pdata;
dev_dbg(i2c_p->dev, "%s\n", __func__);
return 0;
}
static int i2c_prepare_amodel_loading(struct dbmdx_private *p)
{
struct dbmdx_i2c_private *i2c_p =
(struct dbmdx_i2c_private *)p->chip->pdata;
dev_dbg(i2c_p->dev, "%s\n", __func__);
return 0;
}
static int i2c_finish_amodel_loading(struct dbmdx_private *p)
{
struct dbmdx_i2c_private *i2c_p =
(struct dbmdx_i2c_private *)p->chip->pdata;
dev_dbg(i2c_p->dev, "%s\n", __func__);
return 0;
}
static u32 i2c_get_read_chunk_size(struct dbmdx_private *p)
{
struct dbmdx_i2c_private *i2c_p =
(struct dbmdx_i2c_private *)p->chip->pdata;
dev_dbg(i2c_p->dev, "%s I2C read chunk is %u\n",
__func__, i2c_p->pdata->read_chunk_size);
return i2c_p->pdata->read_chunk_size;
}
static u32 i2c_get_write_chunk_size(struct dbmdx_private *p)
{
struct dbmdx_i2c_private *i2c_p =
(struct dbmdx_i2c_private *)p->chip->pdata;
dev_dbg(i2c_p->dev, "%s I2C write chunk is %u\n",
__func__, i2c_p->pdata->write_chunk_size);
return i2c_p->pdata->write_chunk_size;
}
static int i2c_set_read_chunk_size(struct dbmdx_private *p, u32 size)
{
struct dbmdx_i2c_private *i2c_p =
(struct dbmdx_i2c_private *)p->chip->pdata;
if (size > MAX_I2C_READ_CHUNK_SIZE) {
dev_err(i2c_p->dev,
"%s Error setting I2C read chunk. Max chunk size: %u\n",
__func__, MAX_I2C_READ_CHUNK_SIZE);
return -EINVAL;
} else if ((size % 2) != 0) {
dev_err(i2c_p->dev,
"%s Error setting I2C read chunk. Uneven size\n",
__func__);
return -EINVAL;
} else if (size == 0)
i2c_p->pdata->read_chunk_size = DEFAULT_I2C_READ_CHUNK_SIZE;
else
i2c_p->pdata->read_chunk_size = size;
dev_dbg(i2c_p->dev, "%s I2C read chunk was set to %u\n",
__func__, i2c_p->pdata->read_chunk_size);
return 0;
}
static int i2c_set_write_chunk_size(struct dbmdx_private *p, u32 size)
{
struct dbmdx_i2c_private *i2c_p =
(struct dbmdx_i2c_private *)p->chip->pdata;
if (size > MAX_I2C_WRITE_CHUNK_SIZE) {
dev_err(i2c_p->dev,
"%s Error setting I2C write chunk. Max chunk size: %u\n",
__func__, MAX_I2C_WRITE_CHUNK_SIZE);
return -EINVAL;
} else if ((size % 2) != 0) {
dev_err(i2c_p->dev,
"%s Error setting I2C write chunk. Uneven size\n",
__func__);
return -EINVAL;
} else if (size == 0)
i2c_p->pdata->write_chunk_size = DEFAULT_I2C_WRITE_CHUNK_SIZE;
else
i2c_p->pdata->write_chunk_size = size;
dev_dbg(i2c_p->dev, "%s I2C write chunk was set to %u\n",
__func__, i2c_p->pdata->write_chunk_size);
return 0;
}
int i2c_common_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
#if IS_ENABLED(CONFIG_OF)
struct device_node *np;
#endif
int ret;
struct dbmdx_i2c_private *p;
struct dbmdx_i2c_data *pdata;
dev_dbg(&client->dev, "%s\n", __func__);
p = kzalloc(sizeof(*p), GFP_KERNEL);
if (p == NULL)
return -ENOMEM;
p->client = client;
p->dev = &client->dev;
p->chip.pdata = p;
#if IS_ENABLED(CONFIG_OF)
np = p->dev->of_node;
if (!np) {
dev_err(p->dev, "%s: no devicetree entry\n", __func__);
ret = -EINVAL;
goto out_err_kfree;
}
pdata = kzalloc(sizeof(struct dbmdx_i2c_data), GFP_KERNEL);
if (!pdata) {
ret = -ENOMEM;
goto out_err_kfree;
}
#else
pdata = dev_get_platdata(&client->dev);
if (pdata == NULL) {
dev_err(p->dev, "%s: dbmdx, no platform data found\n",
__func__);
return -ENODEV;
}
#endif
/* remember boot address */
pdata->boot_addr = (u32)(p->client->addr);
#if IS_ENABLED(CONFIG_OF)
ret = of_property_read_u32(np, "operational-addr",
&(pdata->operation_addr));
if (ret != 0) {
/*
* operational address not set, assume it is the same as the
* boot address
*/
pdata->operation_addr = pdata->boot_addr;
dev_info(p->dev, "%s: setting operational addr to boot address\n",
__func__);
}
#endif
dev_info(p->dev, "%s: setting operational addr to 0x%2.2x\n",
__func__, pdata->operation_addr);
#if IS_ENABLED(CONFIG_OF)
ret = of_property_read_u32(np, "read-chunk-size",
&pdata->read_chunk_size);
if (ret != 0) {
/*
* read-chunk-size not set, set it to default
*/
pdata->read_chunk_size = DEFAULT_I2C_READ_CHUNK_SIZE;
dev_info(p->dev,
"%s: Setting i2c read chunk to default val: %u bytes\n",
__func__, pdata->read_chunk_size);
}
#endif
if (pdata->read_chunk_size > MAX_I2C_READ_CHUNK_SIZE)
pdata->read_chunk_size = MAX_I2C_READ_CHUNK_SIZE;
if (pdata->read_chunk_size == 0)
pdata->read_chunk_size = DEFAULT_I2C_READ_CHUNK_SIZE;
dev_info(p->dev, "%s: Setting i2c read chunk to %u bytes\n",
__func__, pdata->read_chunk_size);
#if IS_ENABLED(CONFIG_OF)
ret = of_property_read_u32(np, "write-chunk-size",
&pdata->write_chunk_size);
if (ret != 0) {
/*
* write-chunk-size not set, set it to default
*/
pdata->write_chunk_size = DEFAULT_I2C_WRITE_CHUNK_SIZE;
dev_info(p->dev,
"%s: Setting i2c write chunk to default val: %u bytes\n",
__func__, pdata->write_chunk_size);
}
#endif
if (pdata->write_chunk_size > MAX_I2C_WRITE_CHUNK_SIZE)
pdata->write_chunk_size = MAX_I2C_WRITE_CHUNK_SIZE;
if (pdata->write_chunk_size == 0)
pdata->write_chunk_size = DEFAULT_I2C_WRITE_CHUNK_SIZE;
dev_info(p->dev, "%s: Setting i2c write chunk to %u bytes\n",
__func__, pdata->write_chunk_size);
p->pdata = pdata;
#if IS_ENABLED(CONFIG_PM_WAKELOCKS)
p->ps_nosuspend_wl =
wakeup_source_create("dbmdx_nosuspend_wakelock_i2c");
if (p->ps_nosuspend_wl)
wakeup_source_add(p->ps_nosuspend_wl);
else
dev_err(p->dev,
"%s: Error creating WS: dbmdx_nosuspend_wakelock_i2c\n",
__func__);
#endif
/* fill in chip interface functions */
p->chip.can_boot = i2c_can_boot;
p->chip.prepare_boot = i2c_prepare_boot;
p->chip.finish_boot = i2c_finish_boot;
p->chip.dump = i2c_dump_state;
p->chip.set_va_firmware_ready = i2c_set_va_firmware_ready;
p->chip.set_vqe_firmware_ready = i2c_set_vqe_firmware_ready;
p->chip.transport_enable = i2c_transport_enable;
p->chip.read = read_i2c_data;
p->chip.write = write_i2c_data;
p->chip.send_cmd_va = send_i2c_cmd_va;
p->chip.send_cmd_vqe = send_i2c_cmd_vqe;
p->chip.send_cmd_boot = send_i2c_cmd_boot;
p->chip.verify_boot_checksum = i2c_verify_boot_checksum;
p->chip.prepare_buffering = i2c_prepare_buffering;
p->chip.read_audio_data = i2c_read_audio_data;
p->chip.finish_buffering = i2c_finish_buffering;
p->chip.prepare_amodel_loading = i2c_prepare_amodel_loading;
p->chip.finish_amodel_loading = i2c_finish_amodel_loading;
p->chip.get_write_chunk_size = i2c_get_write_chunk_size;
p->chip.get_read_chunk_size = i2c_get_read_chunk_size;
p->chip.set_write_chunk_size = i2c_set_write_chunk_size;
p->chip.set_read_chunk_size = i2c_set_read_chunk_size;
p->chip.resume = i2c_resume;
p->chip.suspend = i2c_suspend;
p->interface_enabled = 1;
i2c_set_clientdata(client, &p->chip);
dev_info(&client->dev, "%s: successfully probed\n", __func__);
ret = 0;
goto out;
#if IS_ENABLED(CONFIG_OF)
out_err_kfree:
#endif
kfree(p);
out:
return ret;
}
int i2c_common_remove(struct i2c_client *client)
{
struct chip_interface *ci = i2c_get_clientdata(client);
struct dbmdx_i2c_private *p = (struct dbmdx_i2c_private *)ci->pdata;
#if IS_ENABLED(CONFIG_PM_WAKELOCKS)
if (p->ps_nosuspend_wl) {
wakeup_source_remove(p->ps_nosuspend_wl);
wakeup_source_destroy(p->ps_nosuspend_wl);
}
#endif
kfree(p);
i2c_set_clientdata(client, NULL);
return 0;
}