diff options
Diffstat (limited to 'recipes-kernel/linux/linux-yocto-3.8/pxamci-regulator.patch')
-rw-r--r-- | recipes-kernel/linux/linux-yocto-3.8/pxamci-regulator.patch | 135 |
1 files changed, 135 insertions, 0 deletions
diff --git a/recipes-kernel/linux/linux-yocto-3.8/pxamci-regulator.patch b/recipes-kernel/linux/linux-yocto-3.8/pxamci-regulator.patch new file mode 100644 index 0000000..8e7c521 --- /dev/null +++ b/recipes-kernel/linux/linux-yocto-3.8/pxamci-regulator.patch @@ -0,0 +1,135 @@ +From: Marko Katic <dromede.gmail.com> + +Here's an interesting scenario. The spitz machine has an +Intersil 6271A voltage regulator and an ADS7846 touchscreen +controller. + +The ADS7846 driver _requires_ the use of a voltage regulator +or if not present, CONFIG_REGULATOR_DUMMY should be used for proper operation. +This was made mandatory by the following commit: + +======================================== +91143379b01b2020d8878d627ebe9dfb9d6eb4c8 +Input: ads7846 - add regulator support + +The ADS7846/TSC2046 touchscreen controllers can (and usually are) +connected to various regulators for power, so add regulator support. + +Valid regulator will now be required, so boards without complete +regulator setup should either disable regulator framework or enable +CONFIG_REGULATOR_DUMMY. +======================================== + +The ADS7846 in spitz machines is not connected to +any power regulator so it needs CONFIG_REGULATOR_DUMMY enabled. +So to support both the Intersil 6271A regulator and +the ADS7846 controller, CONFIG_REGULATOR and CONFIG_REGULATOR_DUMMY have +to be defined. + +However, enabling CONFIG_REGULATOR and CONFIG_REGULATOR_DUMMY +will break pxamci driver and cause the following error output: + +pxa2xx-mci.0 supply vmmc not found, using dummy regulator +pxa2xx-mci pxa2xx-mci.0: ocr_mask/setpower will not be used +pxa2xx-mci pxa2xx-mci.0: could not set regulator OCR (-22) +pxa2xx-mci pxa2xx-mci.0: unable to set power +pxa2xx-mci pxa2xx-mci.0: could not set regulator OCR (-22) +pxa2xx-mci pxa2xx-mci.0: unable to set power + +Above failures occur in two functions; +pxamci_init_ocr() and pxamci_set_power(). + +Regulator support in pxamci_init_ocr() is not +written with the existence of the dummy regulator driver in +mind. It does not check the return value of mmc_regulator_get_ocrmask() +and it will only fall back to platform data if no regulator was found. + +pxamci_set_power() fails because it does not even try to fall back +to platform data if mmc_regulator_set_ocr() fails. It +expects a proper regulator or no regulator at all. It will +only fall back to platform data if no regulator was found. It does +not properly handle the possible existence of the dummy regulator. + +This patch refactors pxamci_init_ocr() and pxamci_set_power() regulator +support to be more modular, to do more checks and to always fall back +to platform data. + +Signed-off-by: Marko Katic <dromede@gmail.com> +--- + drivers/mmc/host/pxamci.c | 37 ++++++++++++++++++++++++------------- + 1 file changed, 24 insertions(+), 13 deletions(-) + +diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c +index 2b2f65a..6ec1566 100644 +--- a/drivers/mmc/host/pxamci.c ++++ b/drivers/mmc/host/pxamci.c +@@ -83,18 +83,24 @@ struct pxamci_host { + static inline void pxamci_init_ocr(struct pxamci_host *host) + { + #ifdef CONFIG_REGULATOR ++ int ocr_mask; + host->vcc = regulator_get(mmc_dev(host->mmc), "vmmc"); + + if (IS_ERR(host->vcc)) + host->vcc = NULL; + else { +- host->mmc->ocr_avail = mmc_regulator_get_ocrmask(host->vcc); +- if (host->pdata && host->pdata->ocr_mask) ++ ocr_mask = mmc_regulator_get_ocrmask(host->vcc); ++ if (ocr_mask <= 0) ++ host->mmc->ocr_avail = 0; ++ else ++ host->mmc->ocr_avail = ocr_mask; ++ ++ if (host->pdata && host->pdata->ocr_mask && host->mmc->ocr_avail) + dev_warn(mmc_dev(host->mmc), + "ocr_mask/setpower will not be used\n"); + } + #endif +- if (host->vcc == NULL) { ++ if (host->vcc == NULL || host->mmc->ocr_avail == 0) { + /* fall-back to platform data */ + host->mmc->ocr_avail = host->pdata ? + host->pdata->ocr_mask : +@@ -108,26 +114,31 @@ static inline int pxamci_set_power(struct pxamci_host *host, + { + int on; + ++#ifdef CONFIG_REGULATOR + if (host->vcc) { +- int ret; ++ int ret = 0; + +- if (power_mode == MMC_POWER_UP) { ++ if (power_mode == MMC_POWER_UP) + ret = mmc_regulator_set_ocr(host->mmc, host->vcc, vdd); +- if (ret) +- return ret; +- } else if (power_mode == MMC_POWER_OFF) { ++ ++ if (power_mode == MMC_POWER_OFF) + ret = mmc_regulator_set_ocr(host->mmc, host->vcc, 0); +- if (ret) +- return ret; +- } ++ ++ if (ret == 0) ++ return 0; ++ else ++ dev_warn(mmc_dev(host->mmc), ++ "mmc_regulator_set_ocr failed, falling back to platform data\n"); + } +- if (!host->vcc && host->pdata && ++#endif ++ ++ if (host->pdata && + gpio_is_valid(host->pdata->gpio_power)) { + on = ((1 << vdd) & host->pdata->ocr_mask); + gpio_set_value(host->pdata->gpio_power, + !!on ^ host->pdata->gpio_power_invert); + } +- if (!host->vcc && host->pdata && host->pdata->setpower) ++ if (host->pdata && host->pdata->setpower) + host->pdata->setpower(mmc_dev(host->mmc), vdd); + + return 0; |