]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - tas2557sw-android/tas2557-android-driver.git/blobdiff - tas2557-regmap.c
Change Magic Number for kernel 4.19 support
[tas2557sw-android/tas2557-android-driver.git] / tas2557-regmap.c
index 5453d0275e81bb54505ae75fed528a508afb237c..e9befd485964fb0b47855756b5d42166b4194595 100755 (executable)
@@ -103,6 +103,10 @@ static int tas2557_change_book_page(
        }
 
 end:
+       if (nResult < 0)
+               pTAS2557->mnErrCode |= ERROR_DEVA_I2C_COMM;
+       else
+               pTAS2557->mnErrCode &= ~ERROR_DEVA_I2C_COMM;
 
        return nResult;
 }
@@ -136,8 +140,10 @@ static int tas2557_dev_read(
                if (nResult < 0) {
                        dev_err(pTAS2557->dev, "%s, %d, I2C error %d\n",
                                __func__, __LINE__, nResult);
+                       pTAS2557->mnErrCode |= ERROR_DEVA_I2C_COMM;
                        goto end;
-               }
+               } else
+                       pTAS2557->mnErrCode &= ~ERROR_DEVA_I2C_COMM;
                *pValue = Value;
        }
 
@@ -182,9 +188,12 @@ static int tas2557_dev_write(
                                TAS2557_PAGE_ID(nRegister));
        if (nResult >= 0) {
                nResult = regmap_write(pTAS2557->mpRegmap, TAS2557_PAGE_REG(nRegister), nValue);
-               if (nResult < 0)
+               if (nResult < 0) {
                        dev_err(pTAS2557->dev, "%s, %d, I2C error %d\n",
                                __func__, __LINE__, nResult);
+                       pTAS2557->mnErrCode |= ERROR_DEVA_I2C_COMM;
+               } else
+                       pTAS2557->mnErrCode &= ~ERROR_DEVA_I2C_COMM;
        }
 
 end:
@@ -220,9 +229,12 @@ static int tas2557_dev_bulk_read(
                                TAS2557_PAGE_ID(nRegister));
        if (nResult >= 0) {
                nResult = regmap_bulk_read(pTAS2557->mpRegmap, TAS2557_PAGE_REG(nRegister), pData, nLength);
-               if (nResult < 0)
+               if (nResult < 0) {
                        dev_err(pTAS2557->dev, "%s, %d, I2C error %d\n",
                                __func__, __LINE__, nResult);
+                       pTAS2557->mnErrCode |= ERROR_DEVA_I2C_COMM;
+               } else
+                       pTAS2557->mnErrCode &= ~ERROR_DEVA_I2C_COMM;
        }
 
 end:
@@ -258,9 +270,12 @@ static int tas2557_dev_bulk_write(
                                TAS2557_PAGE_ID(nRegister));
        if (nResult >= 0) {
                nResult = regmap_bulk_write(pTAS2557->mpRegmap, TAS2557_PAGE_REG(nRegister), pData, nLength);
-               if (nResult < 0)
+               if (nResult < 0) {
                        dev_err(pTAS2557->dev, "%s, %d, I2C error %d\n",
                                __func__, __LINE__, nResult);
+                       pTAS2557->mnErrCode |= ERROR_DEVA_I2C_COMM;
+               } else
+                       pTAS2557->mnErrCode &= ~ERROR_DEVA_I2C_COMM;
        }
 
 end:
@@ -296,9 +311,12 @@ static int tas2557_dev_update_bits(
                                TAS2557_PAGE_ID(nRegister));
        if (nResult >= 0) {
                nResult = regmap_update_bits(pTAS2557->mpRegmap, TAS2557_PAGE_REG(nRegister), nMask, nValue);
-               if (nResult < 0)
+               if (nResult < 0) {
                        dev_err(pTAS2557->dev, "%s, %d, I2C error %d\n",
                                __func__, __LINE__, nResult);
+                       pTAS2557->mnErrCode |= ERROR_DEVA_I2C_COMM;
+               } else
+                       pTAS2557->mnErrCode &= ~ERROR_DEVA_I2C_COMM;
        }
 
 end:
@@ -318,20 +336,23 @@ void tas2557_clearIRQ(struct tas2557_priv *pTAS2557)
 }
 
 
-void tas2557_enableIRQ(struct tas2557_priv *pTAS2557, bool enable)
+void tas2557_enableIRQ(struct tas2557_priv *pTAS2557, bool enable, bool startup_chk)
 {
        if (enable) {
                if (!pTAS2557->mbIRQEnable) {
-                       if (pTAS2557->mnIRQ != 0)
+                       if (gpio_is_valid(pTAS2557->mnGpioINT)) {
                                enable_irq(pTAS2557->mnIRQ);
-                       pTAS2557->mbIRQEnable = true;
+                               if (startup_chk) {
+                                       /* check after 10 ms */
+                                       schedule_delayed_work(&pTAS2557->irq_work, msecs_to_jiffies(10));
+                               }
+                               pTAS2557->mbIRQEnable = true;
+                       }
                }
        } else {
-               if (pTAS2557->mbIRQEnable) {
-                       if (pTAS2557->mnIRQ != 0)
-                               disable_irq_nosync(pTAS2557->mnIRQ);
-                       pTAS2557->mbIRQEnable = false;
-               }
+               if (gpio_is_valid(pTAS2557->mnGpioINT))
+                       disable_irq_nosync(pTAS2557->mnIRQ);
+               pTAS2557->mbIRQEnable = false;
        }
 }
 
@@ -346,13 +367,17 @@ static void tas2557_hw_reset(struct tas2557_priv *pTAS2557)
 
        pTAS2557->mnCurrentBook = -1;
        pTAS2557->mnCurrentPage = -1;
+       if (pTAS2557->mnErrCode)
+               dev_info(pTAS2557->dev, "before reset, ErrCode=0x%x\n", pTAS2557->mnErrCode);
+       pTAS2557->mnErrCode = 0;
 }
 
 static void irq_work_routine(struct work_struct *work)
 {
        int nResult = 0;
        unsigned int nDevInt1Status = 0, nDevInt2Status = 0;
-       unsigned int nDevPowerUpFlag = 0, nDevPowerStatus = 0;
+       unsigned int nDevPowerUpFlag = 0;
+       int nCounter = 2;
        struct tas2557_priv *pTAS2557 =
                container_of(work, struct tas2557_priv, irq_work.work);
 
@@ -364,44 +389,129 @@ static void irq_work_routine(struct work_struct *work)
        mutex_lock(&pTAS2557->file_lock);
 #endif
 
-       if (!pTAS2557->mbPowerUp)
+       if(pTAS2557->mnErrCode & ERROR_FAILSAFE)
+               goto program;
+
+       if (pTAS2557->mbRuntimeSuspend) {
+               dev_info(pTAS2557->dev, "%s, Runtime Suspended\n", __func__);
+               goto end;
+       }
+
+       if (!pTAS2557->mbPowerUp) {
+               dev_info(pTAS2557->dev, "%s, device not powered\n", __func__);
                goto end;
+       }
 
+       if ((!pTAS2557->mpFirmware->mnConfigurations)
+               || (!pTAS2557->mpFirmware->mnPrograms)) {
+               dev_info(pTAS2557->dev, "%s, firmware not loaded\n", __func__);
+               goto end;
+       }
+       nResult = tas2557_dev_write(pTAS2557, TAS2557_GPIO4_PIN_REG, 0x00);
+       if (nResult < 0)
+               goto program;
        nResult = tas2557_dev_read(pTAS2557, TAS2557_FLAGS_1, &nDevInt1Status);
        if (nResult >= 0)
                nResult = tas2557_dev_read(pTAS2557, TAS2557_FLAGS_2, &nDevInt2Status);
-
        if (nResult < 0)
                goto program;
 
-       if (((nDevInt1Status & 0xdc) != 0) || ((nDevInt2Status & 0x0c) != 0)) {
+       if (((nDevInt1Status & 0xfc) != 0) || ((nDevInt2Status & 0x0c) != 0)) {
                /* in case of INT_OC, INT_UV, INT_OT, INT_BO, INT_CL, INT_CLK1, INT_CLK2 */
                dev_err(pTAS2557->dev, "critical error: 0x%x, 0x%x\n", nDevInt1Status, nDevInt2Status);
+               if (nDevInt1Status & 0x80) {
+                       pTAS2557->mnErrCode |= ERROR_OVER_CURRENT;
+                       dev_err(pTAS2557->dev, "DEVA SPK over current!\n");
+               } else
+                       pTAS2557->mnErrCode &= ~ERROR_OVER_CURRENT;
+
+               if (nDevInt1Status & 0x40) {
+                       pTAS2557->mnErrCode |= ERROR_UNDER_VOLTAGE;
+                       dev_err(pTAS2557->dev, "DEVA SPK under voltage!\n");
+               } else
+                       pTAS2557->mnErrCode &= ~ERROR_UNDER_VOLTAGE;
+
+               if (nDevInt1Status & 0x20) {
+                       pTAS2557->mnErrCode |= ERROR_CLK_HALT;
+                       dev_err(pTAS2557->dev, "DEVA clk halted!\n");
+               } else
+                       pTAS2557->mnErrCode &= ~ERROR_CLK_HALT;
+
+               if (nDevInt1Status & 0x10) {
+                       pTAS2557->mnErrCode |= ERROR_DIE_OVERTEMP;
+                       dev_err(pTAS2557->dev, "DEVA die over temperature!\n");
+               } else
+                       pTAS2557->mnErrCode &= ~ERROR_DIE_OVERTEMP;
+
+               if (nDevInt1Status & 0x08) {
+                       pTAS2557->mnErrCode |= ERROR_BROWNOUT;
+                       dev_err(pTAS2557->dev, "DEVA brownout!\n");
+               } else
+                       pTAS2557->mnErrCode &= ~ERROR_BROWNOUT;
+
+               if (nDevInt1Status & 0x04) {
+                       pTAS2557->mnErrCode |= ERROR_CLK_LOST;
+                       dev_err(pTAS2557->dev, "DEVA clock lost!\n");
+               } else
+                       pTAS2557->mnErrCode &= ~ERROR_CLK_LOST;
+
+               if (nDevInt2Status & 0x08) {
+                       pTAS2557->mnErrCode |= ERROR_CLK_DET1;
+                       dev_err(pTAS2557->dev, "DEVA clk detection 1!\n");
+               } else
+                       pTAS2557->mnErrCode &= ~ERROR_CLK_DET1;
+
+               if (nDevInt2Status & 0x04) {
+                       pTAS2557->mnErrCode |= ERROR_CLK_DET2;
+                       dev_err(pTAS2557->dev, "DEVA clk detection 2!\n");
+               } else
+                       pTAS2557->mnErrCode &= ~ERROR_CLK_DET2;
+
                goto program;
        } else {
-               nResult = tas2557_dev_read(pTAS2557, TAS2557_POWER_UP_FLAG_REG, &nDevPowerUpFlag);
-               if (nResult < 0)
-                       goto program;
-               if ((nDevPowerUpFlag & 0x40) == 0) {
-                       /* Class-D doesn't power on */
-                       nResult = tas2557_dev_read(pTAS2557, TAS2557_POWER_CTRL2_REG, &nDevPowerStatus);
+               dev_dbg(pTAS2557->dev, "IRQ Status: 0x%x, 0x%x\n", nDevInt1Status, nDevInt2Status);
+               nCounter = 2;
+               while (nCounter > 0) {
+                       nResult = tas2557_dev_read(pTAS2557, TAS2557_POWER_UP_FLAG_REG, &nDevPowerUpFlag);
                        if (nResult < 0)
                                goto program;
-                       if (nDevPowerStatus & 0x80)
-                               goto program; /* failed to power on the Class-D */
+                       if ((nDevPowerUpFlag & 0xc0) == 0xc0)
+                               break;
+                       nCounter--;
+                       if (nCounter > 0) {
+                               /* in case check pow status just after power on TAS2557 */
+                               dev_dbg(pTAS2557->dev, "PowSts: 0x%x, check again after 10ms\n",
+                                       nDevPowerUpFlag);
+                               msleep(10);
+                       }
                }
+               if ((nDevPowerUpFlag & 0xc0) != 0xc0) {
+                       dev_err(pTAS2557->dev, "%s, Critical ERROR B[%d]_P[%d]_R[%d]= 0x%x\n",
+                               __func__,
+                               TAS2557_BOOK_ID(TAS2557_POWER_UP_FLAG_REG),
+                               TAS2557_PAGE_ID(TAS2557_POWER_UP_FLAG_REG),
+                               TAS2557_PAGE_REG(TAS2557_POWER_UP_FLAG_REG),
+                               nDevPowerUpFlag);
+                       pTAS2557->mnErrCode |= ERROR_CLASSD_PWR;
+                       goto program;
+               }
+               pTAS2557->mnErrCode &= ~ERROR_CLASSD_PWR;
 
-               dev_dbg(pTAS2557->dev, "%s: INT1=0x%x, INT2=0x%x; PowerUpFlag=0x%x, PwrStatus=0x%x\n",
-                       __func__, nDevInt1Status, nDevInt2Status, nDevPowerUpFlag, nDevPowerStatus);
+               dev_dbg(pTAS2557->dev, "%s: INT1=0x%x, INT2=0x%x; PowerUpFlag=0x%x\n",
+                       __func__, nDevInt1Status, nDevInt2Status, nDevPowerUpFlag);
                goto end;
        }
 
 program:
        /* hardware reset and reload */
+       nResult = -1;
        tas2557_set_program(pTAS2557, pTAS2557->mnCurrentProgram, pTAS2557->mnCurrentConfiguration);
 
 end:
-
+       if (nResult >= 0) {
+               tas2557_dev_write(pTAS2557, TAS2557_GPIO4_PIN_REG, 0x07);
+               tas2557_enableIRQ(pTAS2557, true, false);
+       }
 #ifdef CONFIG_TAS2557_MISC
        mutex_unlock(&pTAS2557->file_lock);
 #endif
@@ -415,7 +525,7 @@ static irqreturn_t tas2557_irq_handler(int irq, void *dev_id)
 {
        struct tas2557_priv *pTAS2557 = (struct tas2557_priv *)dev_id;
 
-       tas2557_enableIRQ(pTAS2557, false);
+       tas2557_enableIRQ(pTAS2557, false, false);
        /* get IRQ status after 100 ms */
        schedule_delayed_work(&pTAS2557->irq_work, msecs_to_jiffies(100));
        return IRQ_HANDLED;
@@ -425,8 +535,13 @@ static enum hrtimer_restart temperature_timer_func(struct hrtimer *timer)
 {
        struct tas2557_priv *pTAS2557 = container_of(timer, struct tas2557_priv, mtimer);
 
-       if (pTAS2557->mbPowerUp)
+       if (pTAS2557->mbPowerUp) {
                schedule_work(&pTAS2557->mtimerwork);
+               if (gpio_is_valid(pTAS2557->mnGpioINT)) {
+                       tas2557_enableIRQ(pTAS2557, false, false);
+                       schedule_delayed_work(&pTAS2557->irq_work, msecs_to_jiffies(1));
+               }
+       }
        return HRTIMER_NORESTART;
 }
 
@@ -445,6 +560,11 @@ static void timer_work_routine(struct work_struct *work)
        mutex_lock(&pTAS2557->file_lock);
 #endif
 
+       if (pTAS2557->mbRuntimeSuspend) {
+               dev_info(pTAS2557->dev, "%s, Runtime Suspended\n", __func__);
+               goto end;
+       }
+
        if (!pTAS2557->mpFirmware->mnConfigurations) {
                dev_info(pTAS2557->dev, "%s, firmware not loaded\n", __func__);
                goto end;
@@ -469,8 +589,8 @@ static void timer_work_routine(struct work_struct *work)
                if (!(pTAS2557->mnDieTvReadCounter % LOW_TEMPERATURE_COUNTER)) {
                        nAvg /= LOW_TEMPERATURE_COUNTER;
                        dev_dbg(pTAS2557->dev, "check : avg=%d\n", nAvg);
-                       if ((nAvg & 0x80000000) != 0) {
-                               /* if Die temperature is below ZERO */
+                       if (nAvg < -6) {
+                               /* if Die temperature is below -6 degree C */
                                if (pTAS2557->mnDevCurrentGain != LOW_TEMPERATURE_GAIN) {
                                        nResult = tas2557_set_DAC_gain(pTAS2557, LOW_TEMPERATURE_GAIN);
                                        if (nResult < 0)
@@ -507,23 +627,32 @@ end:
 #endif
 }
 
-#ifdef CONFIG_PM_SLEEP
-static int tas2557_suspend(struct device *dev)
+static int tas2557_runtime_suspend(struct tas2557_priv *pTAS2557)
 {
-       struct tas2557_priv *pTAS2557 = dev_get_drvdata(dev);
-
        dev_dbg(pTAS2557->dev, "%s\n", __func__);
+
+       pTAS2557->mbRuntimeSuspend = true;
+
        if (hrtimer_active(&pTAS2557->mtimer)) {
                dev_dbg(pTAS2557->dev, "cancel die temp timer\n");
                hrtimer_cancel(&pTAS2557->mtimer);
        }
+       if (work_pending(&pTAS2557->mtimerwork)) {
+               dev_dbg(pTAS2557->dev, "cancel timer work\n");
+               cancel_work_sync(&pTAS2557->mtimerwork);
+       }
+       if (gpio_is_valid(pTAS2557->mnGpioINT)) {
+               if (delayed_work_pending(&pTAS2557->irq_work)) {
+                       dev_dbg(pTAS2557->dev, "cancel IRQ work\n");
+                       cancel_delayed_work_sync(&pTAS2557->irq_work);
+               }
+       }
 
        return 0;
 }
 
-static int tas2557_resume(struct device *dev)
+static int tas2557_runtime_resume(struct tas2557_priv *pTAS2557)
 {
-       struct tas2557_priv *pTAS2557 = dev_get_drvdata(dev);
        struct TProgram *pProgram;
 
        dev_dbg(pTAS2557->dev, "%s\n", __func__);
@@ -532,7 +661,7 @@ static int tas2557_resume(struct device *dev)
                goto end;
        }
 
-       if (pTAS2557->mnCurrentProgram >= pTAS2557->mpCalFirmware->mnPrograms) {
+       if (pTAS2557->mnCurrentProgram >= pTAS2557->mpFirmware->mnPrograms) {
                dev_err(pTAS2557->dev, "%s, firmware corrupted\n", __func__);
                goto end;
        }
@@ -547,11 +676,11 @@ static int tas2557_resume(struct device *dev)
                }
        }
 
+       pTAS2557->mbRuntimeSuspend = false;
 end:
 
        return 0;
 }
-#endif
 
 static bool tas2557_volatile(struct device *pDev, unsigned int nRegister)
 {
@@ -627,6 +756,10 @@ static int tas2557_i2c_probe(struct i2c_client *pClient,
        pTAS2557->set_config = tas2557_set_config;
        pTAS2557->set_calibration = tas2557_set_calibration;
        pTAS2557->hw_reset = tas2557_hw_reset;
+       pTAS2557->runtime_suspend = tas2557_runtime_suspend;
+       pTAS2557->runtime_resume = tas2557_runtime_resume;
+       pTAS2557->mnRestart = 0;
+       pTAS2557->mnEdge = 4;
 
        mutex_init(&pTAS2557->dev_lock);
 
@@ -666,7 +799,7 @@ static int tas2557_i2c_probe(struct i2c_client *pClient,
                dev_dbg(pTAS2557->dev, "irq = %d\n", pTAS2557->mnIRQ);
                INIT_DELAYED_WORK(&pTAS2557->irq_work, irq_work_routine);
                nResult = request_threaded_irq(pTAS2557->mnIRQ, tas2557_irq_handler,
-                               NULL, IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+                                       NULL, IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
                                pClient->name, pTAS2557);
                if (nResult < 0) {
                        dev_err(pTAS2557->dev,
@@ -750,19 +883,10 @@ static const struct of_device_id tas2557_of_match[] = {
 MODULE_DEVICE_TABLE(of, tas2557_of_match);
 #endif
 
-#ifdef CONFIG_PM_SLEEP
-static const struct dev_pm_ops tas2557_pm_ops = {
-       SET_SYSTEM_SLEEP_PM_OPS(tas2557_suspend, tas2557_resume)
-};
-#endif
-
 static struct i2c_driver tas2557_i2c_driver = {
        .driver = {
                        .name = "tas2557",
                        .owner = THIS_MODULE,
-#ifdef CONFIG_PM_SLEEP
-                       .pm = &tas2557_pm_ops,
-#endif
 #if defined(CONFIG_OF)
                        .of_match_table = of_match_ptr(tas2557_of_match),
 #endif
@@ -778,4 +902,4 @@ MODULE_AUTHOR("Texas Instruments Inc.");
 MODULE_DESCRIPTION("TAS2557 I2C Smart Amplifier driver");
 MODULE_LICENSE("GPL v2");
 
-#endif
\ No newline at end of file
+#endif