/* LPSS Flags */ #define LPSS_CLK BIT(0) #define LPSS_CLK_GATE BIT(1) #define LPSS_CLK_DIVIDER BIT(2) #define LPSS_LTR BIT(3) #define LPSS_SAVE_CTX BIT(4) /* * For some devices the DSDT AML code for another device turns off the device * before our suspend handler runs, causing us to read/save all 1-s (0xffffffff) * as ctx register values. * Luckily these devices always use the same ctx register values, so we can * work around this by saving the ctx registers once on activation.
*/ #define LPSS_SAVE_CTX_ONCE BIT(5) #define LPSS_NO_D3_DELAY BIT(6)
/* Devices which need to be in D3 before lpss_iosf_enter_d3_state() proceeds */ static u32 pmc_atom_d3_mask = 0xfe000ffe;
/* LPSS run time quirks */ staticunsignedint lpss_quirks;
/* * LPSS_QUIRK_ALWAYS_POWER_ON: override power state for LPSS DMA device. * * The LPSS DMA controller has neither _PS0 nor _PS3 method. Moreover * it can be powered off automatically whenever the last LPSS device goes down. * In case of no power any access to the DMA controller will hang the system. * The behaviour is reproduced on some HP laptops based on Intel BayTrail as * well as on ASuS T100TA transformer. * * This quirk overrides power state of entire LPSS island to keep DMA powered * on whenever we have at least one other device in use.
*/ #define LPSS_QUIRK_ALWAYS_POWER_ON BIT(0)
offset = pdata->dev_desc->prv_offset + LPSS_RESETS;
val = readl(pdata->mmio_base + offset);
val |= LPSS_RESETS_RESET_APB | LPSS_RESETS_RESET_FUNC;
writel(val, pdata->mmio_base + offset);
}
/* * BYT PWM used for backlight control by the i915 driver on systems without * the Crystal Cove PMIC.
*/ staticstruct pwm_lookup byt_pwm_lookup[] = {
PWM_LOOKUP_WITH_MODULE("80860F09:00", 0, "0000:00:02.0", "pwm_soc_backlight", 0, PWM_POLARITY_NORMAL, "pwm-lpss-platform"),
};
staticvoid byt_pwm_setup(struct lpss_private_data *pdata)
{ /* Only call pwm_add_table for the first PWM controller */ if (acpi_dev_uid_match(pdata->adev, 1))
pwm_add_table(byt_pwm_lookup, ARRAY_SIZE(byt_pwm_lookup));
}
/* Expected to always be successfull, but better safe then sorry */ if (!acpi_dev_uid_to_integer(pdata->adev, &uid) && uid) { /* Detect I2C bus shared with PUNIT and ignore its d3 status */
status = acpi_evaluate_integer(handle, "_SEM", NULL, &shared_host); if (ACPI_SUCCESS(status) && shared_host)
pmc_atom_d3_mask &= ~(BIT_LPSS2_F1_I2C1 << (uid - 1));
}
lpss_deassert_reset(pdata);
if (readl(pdata->mmio_base + pdata->dev_desc->prv_offset))
pdata->fixed_clk_rate = 133000000;
writel(0, pdata->mmio_base + LPSS_I2C_ENABLE);
}
/* * BSW PWM1 is used for backlight control by the i915 driver * BSW PWM2 is used for backlight control for fixed (etched into the glass) * touch controls on some models. These touch-controls have specialized * drivers which know they need the "pwm_soc_lpss_2" con-id.
*/ staticstruct pwm_lookup bsw_pwm_lookup[] = {
PWM_LOOKUP_WITH_MODULE("80862288:00", 0, "0000:00:02.0", "pwm_soc_backlight", 0, PWM_POLARITY_NORMAL, "pwm-lpss-platform"),
PWM_LOOKUP_WITH_MODULE("80862289:00", 0, NULL, "pwm_soc_lpss_2", 0, PWM_POLARITY_NORMAL, "pwm-lpss-platform"),
};
staticvoid bsw_pwm_setup(struct lpss_private_data *pdata)
{ /* Only call pwm_add_table for the first PWM controller */ if (acpi_dev_uid_match(pdata->adev, 1))
pwm_add_table(bsw_pwm_lookup, ARRAY_SIZE(bsw_pwm_lookup));
}
/* Please keep this list sorted alphabetically by vendor and model */ staticconststruct dmi_system_id i2c1_dep_missing_dmi_ids[] = {
{
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "T200TA"),
},
},
{}
};
/* * The _DEP method is used to identify dependencies but instead of creating * device links for every handle in _DEP, only links in the following list are * created. That is necessary because, in the general case, _DEP can refer to * devices that might not have drivers, or that are on different buses, or where * the supplier is not enumerated until after the consumer is probed.
*/ staticconststruct lpss_device_links lpss_device_links[] = { /* CHT External sdcard slot controller depends on PMIC I2C ctrl */
{"808622C1", "7", "80860F14", "3", DL_FLAG_PM_RUNTIME}, /* CHT iGPU depends on PMIC I2C controller */
{"808622C1", "7", "LNXVIDEO", NULL, DL_FLAG_PM_RUNTIME}, /* BYT iGPU depends on the Embedded Controller I2C controller (UID 1) */
{"80860F41", "1", "LNXVIDEO", NULL, DL_FLAG_PM_RUNTIME,
i2c1_dep_missing_dmi_ids}, /* BYT CR iGPU depends on PMIC I2C controller (UID 5 on CR) */
{"80860F41", "5", "LNXVIDEO", NULL, DL_FLAG_PM_RUNTIME}, /* BYT iGPU depends on PMIC I2C controller (UID 7 on non CR) */
{"80860F41", "7", "LNXVIDEO", NULL, DL_FLAG_PM_RUNTIME},
};
if (!pdata->mmio_base) { /* Avoid acpi_bus_attach() instantiating a pdev for this dev. */
adev->pnp.type.platform_id = 0; goto out_free;
}
pdata->adev = adev;
pdata->dev_desc = dev_desc;
if (dev_desc->setup)
dev_desc->setup(pdata);
if (dev_desc->flags & LPSS_CLK) {
ret = register_device_clock(adev, pdata); if (ret) goto out_free;
}
/* * This works around a known issue in ACPI tables where LPSS devices * have _PS0 and _PS3 without _PSC (and no power resources), so * acpi_bus_init_power() will assume that the BIOS has put them into D0.
*/
acpi_device_fix_up_power(adev);
adev->driver_data = pdata;
pdev = acpi_create_platform_device(adev, dev_desc->properties); if (IS_ERR_OR_NULL(pdev)) {
adev->driver_data = NULL;
ret = PTR_ERR(pdev); goto err_out;
}
#ifdef CONFIG_PM /** * acpi_lpss_save_ctx() - Save the private registers of LPSS device * @dev: LPSS device * @pdata: pointer to the private data of the LPSS device * * Most LPSS devices have private registers which may loose their context when * the device is powered down. acpi_lpss_save_ctx() saves those registers into * prv_reg_ctx array.
*/ staticvoid acpi_lpss_save_ctx(struct device *dev, struct lpss_private_data *pdata)
{ unsignedint i;
for (i = 0; i < LPSS_PRV_REG_COUNT; i++) { unsignedlong offset = i * sizeof(u32);
pdata->prv_reg_ctx[i] = __lpss_reg_read(pdata, offset);
dev_dbg(dev, "saving 0x%08x from LPSS reg at offset 0x%02lx\n",
pdata->prv_reg_ctx[i], offset);
}
}
/** * acpi_lpss_restore_ctx() - Restore the private registers of LPSS device * @dev: LPSS device * @pdata: pointer to the private data of the LPSS device * * Restores the registers that were previously stored with acpi_lpss_save_ctx().
*/ staticvoid acpi_lpss_restore_ctx(struct device *dev, struct lpss_private_data *pdata)
{ unsignedint i;
for (i = 0; i < LPSS_PRV_REG_COUNT; i++) { unsignedlong offset = i * sizeof(u32);
__lpss_reg_write(pdata->prv_reg_ctx[i], pdata, offset);
dev_dbg(dev, "restoring 0x%08x to LPSS reg at offset 0x%02lx\n",
pdata->prv_reg_ctx[i], offset);
}
}
staticvoid acpi_lpss_d3_to_d0_delay(struct lpss_private_data *pdata)
{ /* * The following delay is needed or the subsequent write operations may * fail. The LPSS devices are actually PCI devices and the PCI spec * expects 10ms delay before the device can be accessed after D3 to D0 * transition. However some platforms like BSW does not need this delay.
*/ unsignedint delay = 10; /* default 10ms delay */
if (pdata->dev_desc->flags & LPSS_NO_D3_DELAY)
delay = 0;
/* * This is called only on ->probe() stage where a device is either in * known state defined by BIOS or most likely powered off. Due to this * we have to deassert reset line to be sure that ->probe() will * recognize the device.
*/ if (pdata->dev_desc->flags & (LPSS_SAVE_CTX | LPSS_SAVE_CTX_ONCE))
lpss_deassert_reset(pdata);
if (pdata->dev_desc->flags & LPSS_SAVE_CTX_ONCE)
acpi_lpss_save_ctx(dev, pdata);
staticvoid lpss_iosf_enter_d3_state(void)
{
u32 value1 = 0;
u32 mask1 = LPSS_GPIODEF0_DMA_D3_MASK | LPSS_GPIODEF0_DMA_LLP;
u32 value2 = LPSS_PMCSR_D3hot;
u32 mask2 = LPSS_PMCSR_Dx_MASK; /* * PMC provides an information about actual status of the LPSS devices. * Here we read the values related to LPSS power island, i.e. LPSS * devices, excluding both LPSS DMA controllers, along with SCC domain.
*/
u32 func_dis, d3_sts_0, pmc_status; int ret;
ret = pmc_atom_read(PMC_FUNC_DIS, &func_dis); if (ret) return;
mutex_lock(&lpss_iosf_mutex);
ret = pmc_atom_read(PMC_D3_STS_0, &d3_sts_0); if (ret) gotoexit;
/* * Get the status of entire LPSS power island per device basis. * Shutdown both LPSS DMA controllers if and only if all other devices * are already in D3hot.
*/
pmc_status = (~(d3_sts_0 | func_dis)) & pmc_atom_d3_mask; if (pmc_status) gotoexit;
if (pdata->dev_desc->flags & LPSS_SAVE_CTX)
acpi_lpss_save_ctx(dev, pdata);
ret = acpi_dev_suspend(dev, wakeup);
/* * This call must be last in the sequence, otherwise PMC will return * wrong status for devices being about to be powered off. See * lpss_iosf_enter_d3_state() for further information.
*/ if (acpi_target_system_state() == ACPI_STATE_S0 &&
lpss_quirks & LPSS_QUIRK_ALWAYS_POWER_ON && iosf_mbi_available())
lpss_iosf_enter_d3_state();
/* * This call is kept first to be in symmetry with * acpi_lpss_runtime_suspend() one.
*/ if (lpss_quirks & LPSS_QUIRK_ALWAYS_POWER_ON && iosf_mbi_available())
lpss_iosf_exit_d3_state();
ret = acpi_dev_resume(dev); if (ret) return ret;
acpi_lpss_d3_to_d0_delay(pdata);
if (pdata->dev_desc->flags & (LPSS_SAVE_CTX | LPSS_SAVE_CTX_ONCE))
acpi_lpss_restore_ctx(dev, pdata);
return 0;
}
#ifdef CONFIG_PM_SLEEP staticint acpi_lpss_do_suspend_late(struct device *dev)
{ int ret;
if (dev_pm_skip_suspend(dev)) return 0;
ret = pm_generic_suspend_late(dev); return ret ? ret : acpi_lpss_suspend(dev, device_may_wakeup(dev));
}
if (pdata->dev_desc->resume_from_noirq) { /* * The driver's ->suspend_late callback will be invoked by * acpi_lpss_do_suspend_late(), with the assumption that the * driver really wanted to run that code in ->suspend_noirq, but * it could not run after acpi_dev_suspend() and the driver * expected the latter to be called in the "late" phase.
*/
ret = acpi_lpss_do_suspend_late(dev); if (ret) return ret;
}
return acpi_subsys_suspend_noirq(dev);
}
staticint acpi_lpss_do_resume_early(struct device *dev)
{ int ret = acpi_lpss_resume(dev);
return ret ? ret : pm_generic_resume_early(dev);
}
/* Follow acpi_subsys_resume_noirq(). */ if (dev_pm_skip_resume(dev)) return 0;
ret = pm_generic_resume_noirq(dev); if (ret) return ret;
if (!pdata->dev_desc->resume_from_noirq) return 0;
/* * The driver's ->resume_early callback will be invoked by * acpi_lpss_do_resume_early(), with the assumption that the driver * really wanted to run that code in ->resume_noirq, but it could not * run before acpi_dev_resume() and the driver expected the latter to be * called in the "early" phase.
*/ return acpi_lpss_do_resume_early(dev);
}
staticint acpi_lpss_do_restore_early(struct device *dev)
{ int ret = acpi_lpss_resume(dev);
return ret ? ret : pm_generic_restore_early(dev);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.