Message ID | 20171129213300.20021-17-afd@ti.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On Wed, Nov 29, 2017 at 03:32:57PM -0600, Andrew F. Davis wrote: > +static irqreturn_t aic31xx_irq(int irq, void *data) > +{ > + struct aic31xx_priv *aic31xx = (struct aic31xx_priv *)data; There is no need to cast away from void, doing so can only mask bugs. > + ret = regmap_read(aic31xx->regmap, AIC31XX_INTRDACFLAG, &value); > + if (ret) { > + dev_err(dev, "Failed to read interrupt mask: %d\n", ret); > + return IRQ_NONE; > + } > + > + if (value & AIC31XX_HPLSCDETECT) > + dev_err(dev, "Short circuit on Left output is detected\n"); > + if (value & AIC31XX_HPRSCDETECT) > + dev_err(dev, "Short circuit on Right output is detected\n"); > + > + return IRQ_HANDLED; This will report the interrupt as handled even if we didn't see an interrupt we understand which will break shared interrupt lines. At the very least we should log other interrupt sources numerically. > + if (aic31xx->irq > 0) { > + regmap_update_bits(aic31xx->regmap, AIC31XX_GPIO1, > + AIC31XX_GPIO1_FUNC_MASK, > + AIC31XX_GPIO1_INT1 << > + AIC31XX_GPIO1_FUNC_SHIFT); Is the interrupt only available on GPIO1?
On 12/01/2017 07:39 AM, Mark Brown wrote: > On Wed, Nov 29, 2017 at 03:32:57PM -0600, Andrew F. Davis wrote: > >> +static irqreturn_t aic31xx_irq(int irq, void *data) >> +{ >> + struct aic31xx_priv *aic31xx = (struct aic31xx_priv *)data; > > There is no need to cast away from void, doing so can only mask bugs. > >> + ret = regmap_read(aic31xx->regmap, AIC31XX_INTRDACFLAG, &value); >> + if (ret) { >> + dev_err(dev, "Failed to read interrupt mask: %d\n", ret); >> + return IRQ_NONE; >> + } >> + >> + if (value & AIC31XX_HPLSCDETECT) >> + dev_err(dev, "Short circuit on Left output is detected\n"); >> + if (value & AIC31XX_HPRSCDETECT) >> + dev_err(dev, "Short circuit on Right output is detected\n"); >> + >> + return IRQ_HANDLED; > > This will report the interrupt as handled even if we didn't see an > interrupt we understand which will break shared interrupt lines. At the > very least we should log other interrupt sources numerically. > Okay, I think I can make that work by checking if no bits are set in the interrupt regs and returning early if not, IRQ_NONE. >> + if (aic31xx->irq > 0) { >> + regmap_update_bits(aic31xx->regmap, AIC31XX_GPIO1, >> + AIC31XX_GPIO1_FUNC_MASK, >> + AIC31XX_GPIO1_INT1 << >> + AIC31XX_GPIO1_FUNC_SHIFT); > > Is the interrupt only available on GPIO1? > Some devices can route this to GPIO2 IIRC. I'm not sure how that would be supported, I think we would need to add interrupt names to DT so users could specify which gpio they wired their IRQ lines to. interrupt = <&host 23>; interrupt-name = "gpio2"; or similar?
On Fri, Dec 01, 2017 at 09:32:12AM -0600, Andrew F. Davis wrote: > On 12/01/2017 07:39 AM, Mark Brown wrote: > > Is the interrupt only available on GPIO1? > Some devices can route this to GPIO2 IIRC. > I'm not sure how that would be supported, I think we would need to add > interrupt names to DT so users could specify which gpio they wired their > IRQ lines to. > interrupt = <&host 23>; > interrupt-name = "gpio2"; > or similar? You could also use pinctrl an require the user to mux the interrupt in whatever fashion makes sense for their device.
On 12/01/2017 09:57 AM, Mark Brown wrote: > On Fri, Dec 01, 2017 at 09:32:12AM -0600, Andrew F. Davis wrote: >> On 12/01/2017 07:39 AM, Mark Brown wrote: > >>> Is the interrupt only available on GPIO1? > >> Some devices can route this to GPIO2 IIRC. > >> I'm not sure how that would be supported, I think we would need to add >> interrupt names to DT so users could specify which gpio they wired their >> IRQ lines to. > >> interrupt = <&host 23>; >> interrupt-name = "gpio2"; > >> or similar? > > You could also use pinctrl an require the user to mux the interrupt in > whatever fashion makes sense for their device. > If done at that layer then no change is needed in the driver right? We just request and use the IRQ passed to us from i2c data.
On 12/01/2017 09:32 AM, Andrew F. Davis wrote: > On 12/01/2017 07:39 AM, Mark Brown wrote: >> On Wed, Nov 29, 2017 at 03:32:57PM -0600, Andrew F. Davis wrote: >> >>> +static irqreturn_t aic31xx_irq(int irq, void *data) >>> +{ >>> + struct aic31xx_priv *aic31xx = (struct aic31xx_priv *)data; >> >> There is no need to cast away from void, doing so can only mask bugs. >> >>> + ret = regmap_read(aic31xx->regmap, AIC31XX_INTRDACFLAG, &value); >>> + if (ret) { >>> + dev_err(dev, "Failed to read interrupt mask: %d\n", ret); >>> + return IRQ_NONE; >>> + } >>> + >>> + if (value & AIC31XX_HPLSCDETECT) >>> + dev_err(dev, "Short circuit on Left output is detected\n"); >>> + if (value & AIC31XX_HPRSCDETECT) >>> + dev_err(dev, "Short circuit on Right output is detected\n"); >>> + >>> + return IRQ_HANDLED; >> >> This will report the interrupt as handled even if we didn't see an >> interrupt we understand which will break shared interrupt lines. At the >> very least we should log other interrupt sources numerically. >> > > Okay, I think I can make that work by checking if no bits are set in the > interrupt regs and returning early if not, IRQ_NONE. > This turned out to be more difficult than I expected, plus if I do handle an interrupt it doesn't mean the other device did not right? So this wouldn't fix shared lines as far as I can tell, but I don't register it as shared so this should be fine. As for your other suggestion of "log other interrupt sources numerically", could you explain this or point to an example of what you mean? >>> + if (aic31xx->irq > 0) { >>> + regmap_update_bits(aic31xx->regmap, AIC31XX_GPIO1, >>> + AIC31XX_GPIO1_FUNC_MASK, >>> + AIC31XX_GPIO1_INT1 << >>> + AIC31XX_GPIO1_FUNC_SHIFT); >> >> Is the interrupt only available on GPIO1? >> > > Some devices can route this to GPIO2 IIRC. > > I'm not sure how that would be supported, I think we would need to add > interrupt names to DT so users could specify which gpio they wired their > IRQ lines to. > > interrupt = <&host 23>; > interrupt-name = "gpio2"; > > or similar? >
On Wed, Dec 06, 2017 at 02:22:39PM -0600, Andrew F. Davis wrote: > On 12/01/2017 09:32 AM, Andrew F. Davis wrote: > >> This will report the interrupt as handled even if we didn't see an > >> interrupt we understand which will break shared interrupt lines. At the > >> very least we should log other interrupt sources numerically. > > Okay, I think I can make that work by checking if no bits are set in the > > interrupt regs and returning early if not, IRQ_NONE. > This turned out to be more difficult than I expected, plus if I do > handle an interrupt it doesn't mean the other device did not right? So > this wouldn't fix shared lines as far as I can tell, but I don't > register it as shared so this should be fine. It'll mean that we don't offer the interrupt to anything else sharing the line. > As for your other suggestion of "log other interrupt sources > numerically", could you explain this or point to an example of what you > mean? Just print out the bits that were set.
On 12/07/2017 06:03 AM, Mark Brown wrote: > On Wed, Dec 06, 2017 at 02:22:39PM -0600, Andrew F. Davis wrote: >> On 12/01/2017 09:32 AM, Andrew F. Davis wrote: > >>>> This will report the interrupt as handled even if we didn't see an >>>> interrupt we understand which will break shared interrupt lines. At the >>>> very least we should log other interrupt sources numerically. > >>> Okay, I think I can make that work by checking if no bits are set in the >>> interrupt regs and returning early if not, IRQ_NONE. > >> This turned out to be more difficult than I expected, plus if I do >> handle an interrupt it doesn't mean the other device did not right? So >> this wouldn't fix shared lines as far as I can tell, but I don't >> register it as shared so this should be fine. > > It'll mean that we don't offer the interrupt to anything else sharing > the line. > >> As for your other suggestion of "log other interrupt sources >> numerically", could you explain this or point to an example of what you >> mean? > > Just print out the bits that were set. > I don't see anyone else doing this, what would that solve? Maybe I still don't get what you mean here. :(
On Thu, Dec 07, 2017 at 09:37:36AM -0600, Andrew F. Davis wrote: > On 12/07/2017 06:03 AM, Mark Brown wrote: > >> As for your other suggestion of "log other interrupt sources > >> numerically", could you explain this or point to an example of what you > >> mean? > > Just print out the bits that were set. > I don't see anyone else doing this, what would that solve? Maybe I still > don't get what you mean here. :( A good proportion of devices require explicit acks for interrupts and only ack things they handled so don't have this issue, and otherwise it's common to just handle all the interrupts that the device might fire. The goal is to not silently eat interrupts if the device starts interrupting for some reason.
diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index 77ae8f36a943..fd3109366377 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -164,6 +164,7 @@ struct aic31xx_priv { unsigned int sysclk; u8 p_div; int rate_div_line; + int irq; }; struct aic31xx_rate_divs { @@ -1258,6 +1259,27 @@ static const struct acpi_device_id aic31xx_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, aic31xx_acpi_match); #endif +static irqreturn_t aic31xx_irq(int irq, void *data) +{ + struct aic31xx_priv *aic31xx = (struct aic31xx_priv *)data; + struct device *dev = aic31xx->dev; + unsigned int value; + int ret; + + ret = regmap_read(aic31xx->regmap, AIC31XX_INTRDACFLAG, &value); + if (ret) { + dev_err(dev, "Failed to read interrupt mask: %d\n", ret); + return IRQ_NONE; + } + + if (value & AIC31XX_HPLSCDETECT) + dev_err(dev, "Short circuit on Left output is detected\n"); + if (value & AIC31XX_HPRSCDETECT) + dev_err(dev, "Short circuit on Right output is detected\n"); + + return IRQ_HANDLED; +} + static int aic31xx_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { @@ -1280,6 +1302,7 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c, return ret; } aic31xx->dev = &i2c->dev; + aic31xx->irq = i2c->irq; aic31xx->codec_type = id->driver_data; @@ -1318,6 +1341,25 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c, return ret; } + if (aic31xx->irq > 0) { + regmap_update_bits(aic31xx->regmap, AIC31XX_GPIO1, + AIC31XX_GPIO1_FUNC_MASK, + AIC31XX_GPIO1_INT1 << + AIC31XX_GPIO1_FUNC_SHIFT); + + regmap_write(aic31xx->regmap, AIC31XX_INT1CTRL, + AIC31XX_SC); + + ret = devm_request_threaded_irq(aic31xx->dev, aic31xx->irq, + NULL, aic31xx_irq, + IRQF_ONESHOT, "aic31xx-irq", + aic31xx); + if (ret) { + dev_err(aic31xx->dev, "Unable to request IRQ\n"); + return ret; + } + } + if (aic31xx->codec_type & DAC31XX_BIT) return snd_soc_register_codec(&i2c->dev, &soc_codec_driver_aic31xx, diff --git a/sound/soc/codecs/tlv320aic31xx.h b/sound/soc/codecs/tlv320aic31xx.h index ab94e6a0c742..9dc85b6f6ad3 100644 --- a/sound/soc/codecs/tlv320aic31xx.h +++ b/sound/soc/codecs/tlv320aic31xx.h @@ -184,6 +184,22 @@ enum aic31xx_type { #define AIC31XX_SC BIT(3) #define AIC31XX_ENGINE BIT(2) +/* AIC31XX_GPIO1 */ +#define AIC31XX_GPIO1_FUNC_MASK GENMASK(5, 2) +#define AIC31XX_GPIO1_FUNC_SHIFT 2 +#define AIC31XX_GPIO1_DISABLED 0x00 +#define AIC31XX_GPIO1_INPUT 0x01 +#define AIC31XX_GPIO1_GPI 0x02 +#define AIC31XX_GPIO1_GPO 0x03 +#define AIC31XX_GPIO1_CLKOUT 0x04 +#define AIC31XX_GPIO1_INT1 0x05 +#define AIC31XX_GPIO1_INT2 0x06 +#define AIC31XX_GPIO1_ADC_WCLK 0x07 +#define AIC31XX_GPIO1_SBCLK 0x08 +#define AIC31XX_GPIO1_SWCLK 0x09 +#define AIC31XX_GPIO1_ADC_MOD_CLK 0x10 +#define AIC31XX_GPIO1_SDOUT 0x11 + /* AIC31XX_DACSETUP */ #define AIC31XX_SOFTSTEP_MASK GENMASK(1, 0)
These devices support detecting and reporting short circuits across the output stages. Add support for reporting these issue. Do this by registering an interrupt if available and enabling this error to trigger that interrupt in the device. Signed-off-by: Andrew F. Davis <afd@ti.com> --- sound/soc/codecs/tlv320aic31xx.c | 42 ++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/tlv320aic31xx.h | 16 +++++++++++++++ 2 files changed, 58 insertions(+)