misc: cs40l2x: Update part number resolution

* Updated the qualification of the device ID to include part numbers
  programmed by the OTP controller (e.g. revisions B0 and B1).
* Conditionalized OTP memory unpack and application of errata based
  on silicon revision.

Change-Id: I7c8c6f194c6f300e632b3382dca5f54eed6f6603
Signed-off-by: Jeff LaBundy <jeff.labundy@cirrus.com>
Signed-off-by: Ravi Vembu <raviv@motorola.com>
This commit is contained in:
Jeff LaBundy 2018-04-04 13:18:27 -05:00 • committed by a7301c
commit a09b0ec803
2 changed files with 114 additions and 70 deletions

View file

@ -46,6 +46,8 @@ struct cs40l2x_private {
struct regmap *regmap;
struct regulator_bulk_data supplies[2];
unsigned int num_supplies;
unsigned int devid;
unsigned int revid;
struct work_struct vibe_start_work;
struct work_struct vibe_stop_work;
struct workqueue_struct *vibe_workqueue;
@ -78,6 +80,13 @@ static const char * const cs40l2x_supplies[] = {
"VP",
};
static const char * const cs40l2x_part_nums[] = {
"CS40L20",
"CS40L25",
"CS40L25A",
"CS40L25B",
};
static struct cs40l2x_private *cs40l2x_get_private(struct device *dev)
{
#ifdef CONFIG_ANDROID_TIMED_OUTPUT
@ -1537,40 +1546,8 @@ static int cs40l2x_otp_unpack(struct cs40l2x_private *cs40l2x)
unsigned char row_offset, col_offset;
unsigned int val, otp_map;
unsigned int otp_mem[CS40L2X_NUM_OTP_WORDS];
int otp_timeout = CS40L2X_OTP_TIMEOUT_COUNT;
int ret, i;
while (otp_timeout > 0) {
usleep_range(10000, 10100);
ret = regmap_read(regmap, CS40L2X_IRQ1_STATUS4, &val);
if (ret) {
dev_err(dev, "Failed to read OTP boot status\n");
return ret;
}
if (val & CS40L2X_OTP_BOOT_DONE)
break;
otp_timeout--;
}
if (otp_timeout == 0) {
dev_err(dev, "Timed out waiting for OTP boot\n");
return -ETIME;
}
ret = regmap_read(cs40l2x->regmap, CS40L2X_IRQ1_STATUS3, &val);
if (ret) {
dev_err(dev, "Failed to read OTP error status\n");
return ret;
}
if (val & CS40L2X_OTP_BOOT_ERR) {
dev_err(dev, "Encountered fatal OTP error\n");
return -EIO;
}
ret = regmap_read(cs40l2x->regmap, CS40L2X_OTPID, &val);
if (ret) {
dev_err(dev, "Failed to read OTP ID\n");
@ -1721,6 +1698,104 @@ static const struct reg_sequence cs40l2x_rev_a0_errata[] = {
{CS40L2X_IRQ2_DB3, 0x00000000},
};
static int cs40l2x_part_num_resolve(struct cs40l2x_private *cs40l2x)
{
struct regmap *regmap = cs40l2x->regmap;
struct device *dev = cs40l2x->dev;
unsigned int val, devid, revid;
unsigned int part_num_index;
int otp_timeout = CS40L2X_OTP_TIMEOUT_COUNT;
int ret;
while (otp_timeout > 0) {
usleep_range(10000, 10100);
ret = regmap_read(regmap, CS40L2X_IRQ1_STATUS4, &val);
if (ret) {
dev_err(dev, "Failed to read OTP boot status\n");
return ret;
}
if (val & CS40L2X_OTP_BOOT_DONE)
break;
otp_timeout--;
}
if (otp_timeout == 0) {
dev_err(dev, "Timed out waiting for OTP boot\n");
return -ETIME;
}
ret = regmap_read(regmap, CS40L2X_IRQ1_STATUS3, &val);
if (ret) {
dev_err(dev, "Failed to read OTP error status\n");
return ret;
}
if (val & CS40L2X_OTP_BOOT_ERR) {
dev_err(dev, "Encountered fatal OTP error\n");
return -EIO;
}
ret = regmap_read(regmap, CS40L2X_DEVID, &devid);
if (ret) {
dev_err(dev, "Failed to read device ID\n");
return ret;
}
ret = regmap_read(regmap, CS40L2X_REVID, &revid);
if (ret) {
dev_err(dev, "Failed to read revision ID\n");
return ret;
}
switch (devid) {
case CS40L2X_DEVID_L20:
part_num_index = 0;
if (revid != CS40L2X_REVID_A0)
goto err_revid;
ret = regmap_register_patch(regmap, cs40l2x_rev_a0_errata,
ARRAY_SIZE(cs40l2x_rev_a0_errata));
if (ret) {
dev_err(dev, "Failed to apply revision %02X errata\n",
revid);
return ret;
}
ret = cs40l2x_otp_unpack(cs40l2x);
if (ret)
return ret;
break;
case CS40L2X_DEVID_L25:
part_num_index = 1;
if (revid != CS40L2X_REVID_B0)
goto err_revid;
break;
case CS40L2X_DEVID_L25A:
case CS40L2X_DEVID_L25B:
part_num_index = devid - CS40L2X_DEVID_L25A + 2;
if (revid < CS40L2X_REVID_B1)
goto err_revid;
break;
default:
dev_err(dev, "Unrecognized device ID: 0x%06X\n", devid);
return -ENODEV;
}
dev_info(dev, "Cirrus Logic %s revision %02X\n",
cs40l2x_part_nums[part_num_index], revid);
cs40l2x->devid = devid;
cs40l2x->revid = revid;
return 0;
err_revid:
dev_err(dev, "Unexpected revision ID for %s: %02X\n",
cs40l2x_part_nums[part_num_index], revid);
return -ENODEV;
}
static struct regmap_config cs40l2x_regmap = {
.reg_bits = 32,
.val_bits = 32,
@ -1743,7 +1818,6 @@ static int cs40l2x_i2c_probe(struct i2c_client *i2c_client,
struct cs40l2x_private *cs40l2x;
struct device *dev = &i2c_client->dev;
struct cs40l2x_platform_data *pdata = dev_get_platdata(dev);
unsigned int reg_devid, reg_revid;
cs40l2x = devm_kzalloc(dev, sizeof(struct cs40l2x_private), GFP_KERNEL);
if (!cs40l2x)
@ -1810,45 +1884,10 @@ static int cs40l2x_i2c_probe(struct i2c_client *i2c_client,
/* satisfy control port delay specification (with margin) */
usleep_range(1000, 1100);
ret = regmap_read(cs40l2x->regmap, CS40L2X_DEVID, &reg_devid);
if (ret) {
dev_err(dev, "Failed to read device ID\n");
goto err;
}
if (reg_devid != CS40L2X_CHIP_ID) {
dev_err(dev, "Failed to recognize device ID: %X\n", reg_devid);
ret = -ENODEV;
goto err;
}
ret = regmap_read(cs40l2x->regmap, CS40L2X_REVID, &reg_revid);
if (ret) {
dev_err(dev, "Failed to read revision ID\n");
goto err;
}
if (reg_revid != CS40L2X_REVID_A0) {
dev_err(dev, "Failed to recognize revision ID: %02X\n",
reg_revid);
ret = -ENODEV;
goto err;
}
ret = regmap_register_patch(cs40l2x->regmap, cs40l2x_rev_a0_errata,
ARRAY_SIZE(cs40l2x_rev_a0_errata));
if (ret) {
dev_err(dev, "Failed to apply revision %02X errata\n",
reg_revid);
goto err;
}
ret = cs40l2x_otp_unpack(cs40l2x);
ret = cs40l2x_part_num_resolve(cs40l2x);
if (ret)
goto err;
dev_info(dev, "Cirrus Logic CS40L20 revision %02X\n", reg_revid);
ret = cs40l2x_init(cs40l2x);
if (ret)
goto err;

View file

@ -669,9 +669,14 @@
#define CS40L2X_INT1_UNMASK_PUP 0xFEFFFFFF
#define CS40L2X_INT1_UNMASK_PDN 0xFF7FFFFF
#define CS40L2X_CHIP_ID 0x35A40
#define CS40L2X_DEVID_L20 0x035A40
#define CS40L2X_DEVID_L25 0x40A250
#define CS40L2X_DEVID_L25A 0x40A25A
#define CS40L2X_DEVID_L25B 0x40A25B
#define CS40L2X_REVID_A0 0xA0
#define CS40L2X_REVID_B0 0xB0
#define CS40L2X_REVID_B1 0xB1
#define CS40L2X_MPU_UNLOCK_CODE1 0x5555
#define CS40L2X_MPU_UNLOCK_CODE2 0xAAAA