mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-16 00:51:51 -04:00
ASoC: Correct bug parsing DisCo booleans
Charles Keepax <ckeepax@opensource.cirrus.com> says: MIPI DisCo uses the unfortunate convention of allowing boolean properties to be present but having a zero value. Opposed to the normal convention of simply not specifying the property. Fix an issue in the SDCA code where mipi-sdca-control-deferrable is not parsed correctly. However, we also have some shipping ACPIs where these properties are not specified correctly. Update the MBQ regmap to attempt defers albeit with a warning in the case where a control attempts to defer but is not marked at such. There is little down side to this as if defer is genuinely not supported then the control will just return the same error again.
This commit is contained in:
@@ -74,7 +74,7 @@ static int regmap_sdw_mbq_poll_busy(struct sdw_slave *slave, unsigned int reg,
|
||||
|
||||
static int regmap_sdw_mbq_write_impl(struct sdw_slave *slave,
|
||||
unsigned int reg, unsigned int val,
|
||||
int mbq_size, bool deferrable)
|
||||
int mbq_size)
|
||||
{
|
||||
int shift = mbq_size * BITS_PER_BYTE;
|
||||
int ret;
|
||||
@@ -88,17 +88,14 @@ static int regmap_sdw_mbq_write_impl(struct sdw_slave *slave,
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = sdw_write_no_pm(slave, reg, val & 0xff);
|
||||
if (deferrable && ret == -ENODATA)
|
||||
return -EAGAIN;
|
||||
|
||||
return ret;
|
||||
return sdw_write_no_pm(slave, reg, val & 0xff);
|
||||
}
|
||||
|
||||
static int regmap_sdw_mbq_write(void *context, unsigned int reg, unsigned int val)
|
||||
{
|
||||
struct regmap_mbq_context *ctx = context;
|
||||
struct sdw_slave *slave = ctx->sdw;
|
||||
struct device *dev = ctx->dev;
|
||||
bool deferrable = regmap_sdw_mbq_deferrable(ctx, reg);
|
||||
int mbq_size = regmap_sdw_mbq_size(ctx, reg);
|
||||
int ret;
|
||||
@@ -113,13 +110,16 @@ static int regmap_sdw_mbq_write(void *context, unsigned int reg, unsigned int va
|
||||
* process a single wait/timeout on function busy and a single retry
|
||||
* of the transaction.
|
||||
*/
|
||||
ret = regmap_sdw_mbq_write_impl(slave, reg, val, mbq_size, deferrable);
|
||||
if (ret == -EAGAIN) {
|
||||
ret = regmap_sdw_mbq_write_impl(slave, reg, val, mbq_size);
|
||||
if (ret == -ENODATA) {
|
||||
if (!deferrable)
|
||||
dev_warn(dev, "Defer on undeferrable control: %x\n", reg);
|
||||
|
||||
ret = regmap_sdw_mbq_poll_busy(slave, reg, ctx);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regmap_sdw_mbq_write_impl(slave, reg, val, mbq_size, false);
|
||||
ret = regmap_sdw_mbq_write_impl(slave, reg, val, mbq_size);
|
||||
}
|
||||
|
||||
return ret;
|
||||
@@ -127,18 +127,14 @@ static int regmap_sdw_mbq_write(void *context, unsigned int reg, unsigned int va
|
||||
|
||||
static int regmap_sdw_mbq_read_impl(struct sdw_slave *slave,
|
||||
unsigned int reg, unsigned int *val,
|
||||
int mbq_size, bool deferrable)
|
||||
int mbq_size)
|
||||
{
|
||||
int shift = BITS_PER_BYTE;
|
||||
int read;
|
||||
|
||||
read = sdw_read_no_pm(slave, reg);
|
||||
if (read < 0) {
|
||||
if (deferrable && read == -ENODATA)
|
||||
return -EAGAIN;
|
||||
|
||||
if (read < 0)
|
||||
return read;
|
||||
}
|
||||
|
||||
*val = read;
|
||||
|
||||
@@ -158,6 +154,7 @@ static int regmap_sdw_mbq_read(void *context, unsigned int reg, unsigned int *va
|
||||
{
|
||||
struct regmap_mbq_context *ctx = context;
|
||||
struct sdw_slave *slave = ctx->sdw;
|
||||
struct device *dev = ctx->dev;
|
||||
bool deferrable = regmap_sdw_mbq_deferrable(ctx, reg);
|
||||
int mbq_size = regmap_sdw_mbq_size(ctx, reg);
|
||||
int ret;
|
||||
@@ -172,13 +169,16 @@ static int regmap_sdw_mbq_read(void *context, unsigned int reg, unsigned int *va
|
||||
* process a single wait/timeout on function busy and a single retry
|
||||
* of the transaction.
|
||||
*/
|
||||
ret = regmap_sdw_mbq_read_impl(slave, reg, val, mbq_size, deferrable);
|
||||
if (ret == -EAGAIN) {
|
||||
ret = regmap_sdw_mbq_read_impl(slave, reg, val, mbq_size);
|
||||
if (ret == -ENODATA) {
|
||||
if (!deferrable)
|
||||
dev_warn(dev, "Defer on undeferable control: %x\n", reg);
|
||||
|
||||
ret = regmap_sdw_mbq_poll_busy(slave, reg, ctx);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regmap_sdw_mbq_read_impl(slave, reg, val, mbq_size, false);
|
||||
ret = regmap_sdw_mbq_read_impl(slave, reg, val, mbq_size);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
@@ -1006,8 +1006,11 @@ static int find_sdca_entity_control(struct device *dev, struct sdca_entity *enti
|
||||
control->has_fixed = true;
|
||||
fallthrough;
|
||||
case SDCA_ACCESS_MODE_RO:
|
||||
control->deferrable = fwnode_property_read_bool(control_node,
|
||||
"mipi-sdca-control-deferrable");
|
||||
ret = fwnode_property_read_u32(control_node,
|
||||
"mipi-sdca-control-deferrable",
|
||||
&tmp);
|
||||
if (ret == 0)
|
||||
control->deferrable = !!tmp;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user