mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-09 21:59:12 -04:00
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:
parent
a0cad12b61
commit
a09b0ec803
2 changed files with 114 additions and 70 deletions
|
|
@ -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, ®_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, ®_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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in a new issue