diff options
Diffstat (limited to 'drivers/mfd/m4sensorhub-reg.c')
| -rw-r--r-- | drivers/mfd/m4sensorhub-reg.c | 151 |
1 files changed, 100 insertions, 51 deletions
diff --git a/drivers/mfd/m4sensorhub-reg.c b/drivers/mfd/m4sensorhub-reg.c index d4e052aa752..9291f0d6e0e 100644 --- a/drivers/mfd/m4sensorhub-reg.c +++ b/drivers/mfd/m4sensorhub-reg.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Motorola, Inc. + * Copyright (C) 2012-2014 Motorola, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -51,9 +51,13 @@ static DEFINE_MUTEX(reg_access); m4sensorhub - pointer to the main m4sensorhub data struct */ - int m4sensorhub_reg_init(struct m4sensorhub_data *m4sensorhub) { + if (m4sensorhub == NULL) { + KDEBUG(M4SH_ERROR, "%s: M4 data is NULL\n", __func__); + return -ENODATA; + } + return 0; } EXPORT_SYMBOL_GPL(m4sensorhub_reg_init); @@ -66,9 +70,13 @@ EXPORT_SYMBOL_GPL(m4sensorhub_reg_init); m4sensorhub - pointer to the main m4sensorhub data struct */ - int m4sensorhub_reg_shutdown(struct m4sensorhub_data *m4sensorhub) { + if (m4sensorhub == NULL) { + KDEBUG(M4SH_ERROR, "%s: M4 data is NULL\n", __func__); + return -ENODATA; + } + return 0; } EXPORT_SYMBOL_GPL(m4sensorhub_reg_shutdown); @@ -86,27 +94,33 @@ EXPORT_SYMBOL_GPL(m4sensorhub_reg_shutdown); value - array to return data. Needs to be at least register's size num - number of bytes to read */ - int m4sensorhub_reg_read_n(struct m4sensorhub_data *m4sensorhub, enum m4sensorhub_reg reg, unsigned char *value, short num) { int ret = -EINVAL; u8 stack_buf[M4SH_MAX_STACK_BUF_SIZE]; + u8 *buf = NULL; - if (!m4sensorhub || !value || !num) { - KDEBUG(M4SH_ERROR, "%s() invalid parameter\n", __func__); - return ret; + if (m4sensorhub == NULL) { + KDEBUG(M4SH_ERROR, "%s: M4 data is NULL\n", __func__); + return -ENODATA; + } else if (value == NULL) { + KDEBUG(M4SH_ERROR, "%s: value array is NULL\n", __func__); + return -ENODATA; + } else if (num == 0) { + KDEBUG(M4SH_ERROR, "%s: Bytes requested is 0\n", __func__); + return -EINVAL; } - if ((reg < M4SH_REG__NUM) && num <= M4SH_MAX_REG_SIZE &&\ + if ((reg < M4SH_REG__NUM) && num <= M4SH_MAX_REG_SIZE && register_info_tbl[reg].offset + num <= m4sensorhub_mapsize(reg)) { - u8 *buf = (num > (M4SH_MAX_STACK_BUF_SIZE-2))\ + buf = (num > (M4SH_MAX_STACK_BUF_SIZE-2)) ? kmalloc(num+2, GFP_KERNEL) : stack_buf; if (!buf) { - KDEBUG(M4SH_ERROR, "%s() Failed alloc %d memeory\n"\ - , __func__, num+2); + KDEBUG(M4SH_ERROR, "%s() Failed alloc %d memory\n", + __func__, num+2); return -ENOMEM; } buf[0] = register_info_tbl[reg].type; @@ -115,11 +129,13 @@ int m4sensorhub_reg_read_n(struct m4sensorhub_data *m4sensorhub, mutex_lock(®_access); ret = m4sensorhub_i2c_write_read(m4sensorhub, buf, 2, num); mutex_unlock(®_access); - - if (ret != num) - KDEBUG(M4SH_ERROR, "%s() read failure\n", __func__); - else + if (ret != num) { + KDEBUG(M4SH_ERROR, "%s() read failure (ret=%d)\n", + __func__, ret); + } else { memcpy(value, buf, num); + } + if (buf != stack_buf) kfree(buf); } else { @@ -128,6 +144,7 @@ int m4sensorhub_reg_read_n(struct m4sensorhub_data *m4sensorhub, reg, M4SH_REG__NUM, num, M4SH_MAX_REG_SIZE, m4sensorhub_mapsize(reg)); } + return ret; } EXPORT_SYMBOL_GPL(m4sensorhub_reg_read_n); @@ -147,27 +164,34 @@ EXPORT_SYMBOL_GPL(m4sensorhub_reg_read_n); are to be changed, then &m4sh_no_mask can be passed here. num - number of bytes to write */ - int m4sensorhub_reg_write_n(struct m4sensorhub_data *m4sensorhub, enum m4sensorhub_reg reg, unsigned char *value, unsigned char *mask, short num) { - int i, ret = -EINVAL; + int i = 0; + int ret = -EINVAL; u8 stack_buf[M4SH_MAX_STACK_BUF_SIZE]; + u8 *buf = NULL; - if (!m4sensorhub || !value || !num) { - KDEBUG(M4SH_ERROR, "%s() invalid parameter\n", __func__); - return ret; + if (m4sensorhub == NULL) { + KDEBUG(M4SH_ERROR, "%s: M4 data is NULL\n", __func__); + return -ENODATA; + } else if (value == NULL) { + KDEBUG(M4SH_ERROR, "%s: value array is NULL\n", __func__); + return -ENODATA; + } else if (num == 0) { + KDEBUG(M4SH_ERROR, "%s: Bytes requested is 0\n", __func__); + return -EINVAL; } - if ((reg < M4SH_REG__NUM) && num <= M4SH_MAX_REG_SIZE &&\ + if ((reg < M4SH_REG__NUM) && num <= M4SH_MAX_REG_SIZE && register_info_tbl[reg].offset + num <= m4sensorhub_mapsize(reg)) { - u8 *buf = (num > (M4SH_MAX_STACK_BUF_SIZE-2))\ + buf = (num > (M4SH_MAX_STACK_BUF_SIZE-2)) ? kmalloc(num+2, GFP_KERNEL) : stack_buf; if (!buf) { - KDEBUG(M4SH_ERROR, "%s() Failed alloc %d memeory\n"\ - , __func__, num+2); + KDEBUG(M4SH_ERROR, "%s() Failed alloc %d memory\n", + __func__, num+2); return -ENOMEM; } @@ -180,7 +204,8 @@ int m4sensorhub_reg_write_n(struct m4sensorhub_data *m4sensorhub, 2, num); if (ret != num) { KDEBUG(M4SH_ERROR, "%s() register read" - "failure\n", __func__); + "failure (ret=%d)\n", + __func__, ret); goto error; } /* move data right 2 positions and apply mask and @@ -200,10 +225,12 @@ int m4sensorhub_reg_write_n(struct m4sensorhub_data *m4sensorhub, KDEBUG(M4SH_ERROR, "%s() register write failure\n", __func__); ret = -EINVAL; - } else + } else { ret -= 2; + } -error: mutex_unlock(®_access); +error: + mutex_unlock(®_access); if (buf != stack_buf) kfree(buf); } else { @@ -230,11 +257,15 @@ EXPORT_SYMBOL_GPL(m4sensorhub_reg_write_n); value - byte of data to write mask - mask representing which bits to change in register. */ - int m4sensorhub_reg_write_1byte(struct m4sensorhub_data *m4sensorhub, enum m4sensorhub_reg reg, unsigned char value, unsigned char mask) { + if (m4sensorhub == NULL) { + KDEBUG(M4SH_ERROR, "%s: M4 data is NULL\n", __func__); + return -ENODATA; + } + if (register_info_tbl[reg].size == 1) { if (mask == 0xFF) { return m4sensorhub_reg_write( @@ -245,6 +276,9 @@ int m4sensorhub_reg_write_1byte(struct m4sensorhub_data *m4sensorhub, m4sensorhub, reg, &value, &mask ); } + } else { + KDEBUG(M4SH_ERROR, "%s: Size is %hu instead of 1\n", + __func__, register_info_tbl[reg].size); } return -EINVAL; } @@ -260,10 +294,14 @@ EXPORT_SYMBOL_GPL(m4sensorhub_reg_write_1byte); m4sensorhub - pointer to the main m4sensorhub data struct reg - Register to get size of */ - int m4sensorhub_reg_getsize(struct m4sensorhub_data *m4sensorhub, enum m4sensorhub_reg reg) { + if (m4sensorhub == NULL) { + KDEBUG(M4SH_ERROR, "%s: M4 data is NULL\n", __func__); + return -ENODATA; + } + if (reg < M4SH_REG__NUM) return register_info_tbl[reg].size; @@ -276,7 +314,6 @@ EXPORT_SYMBOL_GPL(m4sensorhub_reg_getsize); Lock reg access to avoid broken I2C transmit process */ - void m4sensorhub_reg_access_lock(void) { mutex_lock(®_access); @@ -288,7 +325,6 @@ EXPORT_SYMBOL_GPL(m4sensorhub_reg_access_lock); Unlock reg access to wake up blocked I2C transmit process */ - void m4sensorhub_reg_access_unlock(void) { mutex_unlock(®_access); @@ -298,7 +334,7 @@ EXPORT_SYMBOL_GPL(m4sensorhub_reg_access_unlock); /* m4sensorhub_i2c_write_read() Directly I2C access to communicate with the M4 sensor hub. - It always read after write if both write and read length are non-zero + Reads are always after writes if both write and read lengths are non-zero Returns number of bytes write on success if readlen is zero Returns number of bytes read on success if readlen is non-zero @@ -309,29 +345,33 @@ EXPORT_SYMBOL_GPL(m4sensorhub_reg_access_unlock); writelen - number of bytes write to readlen - number of bytes read from */ - int m4sensorhub_i2c_write_read(struct m4sensorhub_data *m4sensorhub, u8 *buf, int writelen, int readlen) { int i, msglen, msgstart, err, tries = 0; char buffer[DEBUG_LINE_LENGTH]; - struct i2c_msg msgs[] = { - { - .addr = m4sensorhub->i2c_client->addr, - .flags = m4sensorhub->i2c_client->flags, - .len = writelen, - .buf = buf, - }, - { - .addr = m4sensorhub->i2c_client->addr, - .flags = m4sensorhub->i2c_client->flags | I2C_M_RD, - .len = readlen, - .buf = buf, - }, - }; + struct i2c_msg msgs[2]; + + if (m4sensorhub == NULL) { + KDEBUG(M4SH_ERROR, "%s: M4 data is NULL\n", __func__); + return -ENODATA; + } else if (buf == NULL) { + KDEBUG(M4SH_ERROR, "%s: Buffer is NULL\n", __func__); + return -ENODATA; + } else if ((writelen == 0) && (readlen == 0)) { + KDEBUG(M4SH_ERROR, "%s: Lengths are both 0\n", __func__); + return -EINVAL; + } + + msgs[0].addr = m4sensorhub->i2c_client->addr; + msgs[0].flags = m4sensorhub->i2c_client->flags; + msgs[0].len = writelen; + msgs[0].buf = buf; - if (buf == NULL || (writelen == 0 && readlen == 0)) - return -EFAULT; + msgs[1].addr = m4sensorhub->i2c_client->addr; + msgs[1].flags = m4sensorhub->i2c_client->flags | I2C_M_RD; + msgs[1].len = readlen; + msgs[1].buf = buf; /* Offset and size in msgs array depending on msg type */ msglen = (writelen && readlen) ? 2 : 1; @@ -352,11 +392,19 @@ int m4sensorhub_i2c_write_read(struct m4sensorhub_data *m4sensorhub, do { err = i2c_transfer(m4sensorhub->i2c_client->adapter, &msgs[msgstart], msglen); - if (err != msglen) + if (err != msglen) { + /* TODO: Print on try 0 after M4 stops NACKing */ + if (tries != 0) { + KDEBUG(M4SH_ERROR, + "%s: Fail on try %d (err=%d)\n", + __func__, tries, err); + } usleep_range(I2C_RETRY_DELAY_MIN, I2C_RETRY_DELAY_MAX); + } } while ((err != msglen) && (++tries < I2C_RETRIES)); + if (err != msglen) { - dev_err(&m4sensorhub->i2c_client->dev, "i2c transfer error; " + dev_err(&m4sensorhub->i2c_client->dev, "i2c transfer error: " "type=%d offset=%d\n", buf[0], buf[1]); err = -EIO; } else { @@ -376,6 +424,7 @@ int m4sensorhub_i2c_write_read(struct m4sensorhub_data *m4sensorhub, KDEBUG(M4SH_VERBOSE_DEBUG, "%s\n", buffer); } } + return err; } EXPORT_SYMBOL_GPL(m4sensorhub_i2c_write_read); |