Merge tag 'mfd-next-4.15' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd

Pull MFD updates from Lee Jones:
 "New drivers:
   - Add support for Cherry Trail Dollar Cove TI PMIC
   - Add support for Add Spreadtrum SC27xx series PMICs

  New device support:
   - Add support Regulator to axp20x

  New functionality:
   - Add DT support; aspeed-scu sc27xx-pmic
   - Add power saving support; rts5249

  Fix-ups:
   - DT clean-up/rework; tps65217, max77693, iproc-cdru, iproc-mhb, tps65218
   - Staticise/constify; stw481x
   - Use new succinct IRQ API; fsl-imx25-tsadc
   - Kconfig fix-ups; MFD_TPS65218
   - Identify SPI method; lpc_ich
   - Use managed resources (devm_*) calls; ssbi
   - Remove unused/obsolete code/documentation; mc13xxx

  Bug fixes:
   - Fix typo in MAINTAINERS
   - Fix error handling; mxs-lradc
   - Clean-up IRQs on .remove; fsl-imx25-tsadc"

* tag 'mfd-next-4.15' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd: (21 commits)
  dt-bindings: mfd: mc13xxx: Remove obsolete property
  mfd: axp20x: Add axp20x-regulator cell for AXP813
  mfd: Add Spreadtrum SC27xx series PMICs driver
  dt-bindings: mfd: Add Spreadtrum SC27xx PMIC documentation
  mfd: ssbi: Use devm_of_platform_populate()
  mfd: fsl-imx25: Clean up irq settings during removal
  mfd: mxs-lradc: Fix error handling in mxs_lradc_probe()
  mfd: lpc_ich: Avoton/Rangeley uses SPI_BYT method
  mfd: tps65218: Introduce dependency on CONFIG_OF
  mfd: tps65218: Correct the config description
  MAINTAINERS: Fix Dialog search term for watchdog binding file
  mfd: fsl-imx25: Set irq handler and data in one go
  mfd: rts5249: Add support for RTS5250S power saving
  ACPI / PMIC: Add opregion driver for Intel Dollar Cove TI PMIC
  mfd: Add support for Cherry Trail Dollar Cove TI PMIC
  syscon: dt-bindings: Add binding document for iProc MHB block
  syscon: dt-bindings: Add binding doc for Broadcom iProc CDRU
  mfd: max77693: Add muic of_compatible in mfd_cell
  mfd: stw481x: Make three arrays static const, reduces object code size
  mfd: tps65217: Introduce dependency on CONFIG_OF
  ...
这个提交包含在:
Linus Torvalds
2017-11-16 09:15:57 -08:00
当前提交 d3092e4e99
修改 30 个文件,包含 1138 行新增75 行删除

查看文件

@@ -510,6 +510,19 @@ config INTEL_SOC_PMIC_CHTWC
available before any devices using it are probed. This option also
causes the designware-i2c driver to be builtin for the same reason.
config INTEL_SOC_PMIC_CHTDC_TI
tristate "Support for Intel Cherry Trail Dollar Cove TI PMIC"
depends on GPIOLIB
depends on I2C
depends on ACPI
depends on X86
select MFD_CORE
select REGMAP_I2C
select REGMAP_IRQ
help
Select this option for supporting Dollar Cove (TI version) PMIC
device that is found on some Intel Cherry Trail systems.
config MFD_INTEL_LPSS
tristate
select COMMON_CLK
@@ -1057,6 +1070,22 @@ config MFD_SMSC
To compile this driver as a module, choose M here: the
module will be called smsc.
config MFD_SC27XX_PMIC
tristate "Spreadtrum SC27xx PMICs"
depends on ARCH_SPRD || COMPILE_TEST
depends on SPI_MASTER
select MFD_CORE
select REGMAP_SPI
select REGMAP_IRQ
help
This enables support for the Spreadtrum SC27xx PMICs with SPI
interface. The SC27xx series PMICs integrate power management,
audio codec, battery management and user interface support
function (such as RTC, Typec, indicator and so on) in a single chip.
This driver provides common support for accessing the SC27xx PMICs,
and it also adds the irq_chip parts for handling the PMIC chip events.
config ABX500_CORE
bool "ST-Ericsson ABX500 Mixed Signal Circuit register functions"
default y if ARCH_U300 || ARCH_U8500 || COMPILE_TEST
@@ -1338,7 +1367,7 @@ config MFD_TPS65090
config MFD_TPS65217
tristate "TI TPS65217 Power Management / White LED chips"
depends on I2C
depends on I2C && OF
select MFD_CORE
select REGMAP_I2C
select IRQ_DOMAIN
@@ -1400,7 +1429,7 @@ config MFD_TI_LP87565
config MFD_TPS65218
tristate "TI TPS65218 Power Management chips"
depends on I2C
depends on I2C && OF
select MFD_CORE
select REGMAP_I2C
select REGMAP_IRQ
@@ -1408,8 +1437,7 @@ config MFD_TPS65218
If you say yes here you get support for the TPS65218 series of
Power Management chips.
These include voltage regulators, gpio and other features
that are often used in portable devices. Only regulator
component is currently supported.
that are often used in portable devices.
This driver can also be built as a module. If so, the module
will be called tps65218.

查看文件

@@ -220,6 +220,7 @@ intel-soc-pmic-objs := intel_soc_pmic_core.o intel_soc_pmic_crc.o
obj-$(CONFIG_INTEL_SOC_PMIC) += intel-soc-pmic.o
obj-$(CONFIG_INTEL_SOC_PMIC_BXTWC) += intel_soc_pmic_bxtwc.o
obj-$(CONFIG_INTEL_SOC_PMIC_CHTWC) += intel_soc_pmic_chtwc.o
obj-$(CONFIG_INTEL_SOC_PMIC_CHTDC_TI) += intel_soc_pmic_chtdc_ti.o
obj-$(CONFIG_MFD_MT6397) += mt6397-core.o
obj-$(CONFIG_MFD_ALTERA_A10SR) += altera-a10sr.o
@@ -228,3 +229,4 @@ obj-$(CONFIG_MFD_SUN4I_GPADC) += sun4i-gpadc.o
obj-$(CONFIG_MFD_STM32_LPTIMER) += stm32-lptimer.o
obj-$(CONFIG_MFD_STM32_TIMERS) += stm32-timers.o
obj-$(CONFIG_MFD_MXS_LRADC) += mxs-lradc.o
obj-$(CONFIG_MFD_SC27XX_PMIC) += sprd-sc27xx-spi.o

查看文件

@@ -876,6 +876,8 @@ static struct mfd_cell axp813_cells[] = {
.name = "axp221-pek",
.num_resources = ARRAY_SIZE(axp803_pek_resources),
.resources = axp803_pek_resources,
}, {
.name = "axp20x-regulator",
}
};

查看文件

@@ -84,8 +84,7 @@ static int mx25_tsadc_setup_irq(struct platform_device *pdev,
return -ENOMEM;
}
irq_set_chained_handler(irq, mx25_tsadc_irq_handler);
irq_set_handler_data(irq, tsadc);
irq_set_chained_handler_and_data(irq, mx25_tsadc_irq_handler, tsadc);
return 0;
}
@@ -180,6 +179,19 @@ static int mx25_tsadc_probe(struct platform_device *pdev)
return devm_of_platform_populate(dev);
}
static int mx25_tsadc_remove(struct platform_device *pdev)
{
struct mx25_tsadc *tsadc = platform_get_drvdata(pdev);
int irq = platform_get_irq(pdev, 0);
if (irq) {
irq_set_chained_handler_and_data(irq, NULL, NULL);
irq_domain_remove(tsadc->domain);
}
return 0;
}
static const struct of_device_id mx25_tsadc_ids[] = {
{ .compatible = "fsl,imx25-tsadc" },
{ /* Sentinel */ }
@@ -192,6 +204,7 @@ static struct platform_driver mx25_tsadc_driver = {
.of_match_table = of_match_ptr(mx25_tsadc_ids),
},
.probe = mx25_tsadc_probe,
.remove = mx25_tsadc_remove,
};
module_platform_driver(mx25_tsadc_driver);

查看文件

@@ -0,0 +1,184 @@
/*
* Device access for Dollar Cove TI PMIC
*
* Copyright (c) 2014, Intel Corporation.
* Author: Ramakrishna Pallala <ramakrishna.pallala@intel.com>
*
* Cleanup and forward-ported
* Copyright (c) 2017 Takashi Iwai <tiwai@suse.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/acpi.h>
#include <linux/interrupt.h>
#include <linux/i2c.h>
#include <linux/mfd/core.h>
#include <linux/mfd/intel_soc_pmic.h>
#include <linux/module.h>
#include <linux/regmap.h>
#define CHTDC_TI_IRQLVL1 0x01
#define CHTDC_TI_MASK_IRQLVL1 0x02
/* Level 1 IRQs */
enum {
CHTDC_TI_PWRBTN = 0, /* power button */
CHTDC_TI_DIETMPWARN, /* thermal */
CHTDC_TI_ADCCMPL, /* ADC */
/* No IRQ 3 */
CHTDC_TI_VBATLOW = 4, /* battery */
CHTDC_TI_VBUSDET, /* power source */
/* No IRQ 6 */
CHTDC_TI_CCEOCAL = 7, /* battery */
};
static struct resource power_button_resources[] = {
DEFINE_RES_IRQ(CHTDC_TI_PWRBTN),
};
static struct resource thermal_resources[] = {
DEFINE_RES_IRQ(CHTDC_TI_DIETMPWARN),
};
static struct resource adc_resources[] = {
DEFINE_RES_IRQ(CHTDC_TI_ADCCMPL),
};
static struct resource pwrsrc_resources[] = {
DEFINE_RES_IRQ(CHTDC_TI_VBUSDET),
};
static struct resource battery_resources[] = {
DEFINE_RES_IRQ(CHTDC_TI_VBATLOW),
DEFINE_RES_IRQ(CHTDC_TI_CCEOCAL),
};
static struct mfd_cell chtdc_ti_dev[] = {
{
.name = "chtdc_ti_pwrbtn",
.num_resources = ARRAY_SIZE(power_button_resources),
.resources = power_button_resources,
}, {
.name = "chtdc_ti_adc",
.num_resources = ARRAY_SIZE(adc_resources),
.resources = adc_resources,
}, {
.name = "chtdc_ti_thermal",
.num_resources = ARRAY_SIZE(thermal_resources),
.resources = thermal_resources,
}, {
.name = "chtdc_ti_pwrsrc",
.num_resources = ARRAY_SIZE(pwrsrc_resources),
.resources = pwrsrc_resources,
}, {
.name = "chtdc_ti_battery",
.num_resources = ARRAY_SIZE(battery_resources),
.resources = battery_resources,
},
{ .name = "chtdc_ti_region", },
};
static const struct regmap_config chtdc_ti_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = 128,
.cache_type = REGCACHE_NONE,
};
static const struct regmap_irq chtdc_ti_irqs[] = {
REGMAP_IRQ_REG(CHTDC_TI_PWRBTN, 0, BIT(CHTDC_TI_PWRBTN)),
REGMAP_IRQ_REG(CHTDC_TI_DIETMPWARN, 0, BIT(CHTDC_TI_DIETMPWARN)),
REGMAP_IRQ_REG(CHTDC_TI_ADCCMPL, 0, BIT(CHTDC_TI_ADCCMPL)),
REGMAP_IRQ_REG(CHTDC_TI_VBATLOW, 0, BIT(CHTDC_TI_VBATLOW)),
REGMAP_IRQ_REG(CHTDC_TI_VBUSDET, 0, BIT(CHTDC_TI_VBUSDET)),
REGMAP_IRQ_REG(CHTDC_TI_CCEOCAL, 0, BIT(CHTDC_TI_CCEOCAL)),
};
static const struct regmap_irq_chip chtdc_ti_irq_chip = {
.name = KBUILD_MODNAME,
.irqs = chtdc_ti_irqs,
.num_irqs = ARRAY_SIZE(chtdc_ti_irqs),
.num_regs = 1,
.status_base = CHTDC_TI_IRQLVL1,
.mask_base = CHTDC_TI_MASK_IRQLVL1,
.ack_base = CHTDC_TI_IRQLVL1,
};
static int chtdc_ti_probe(struct i2c_client *i2c)
{
struct device *dev = &i2c->dev;
struct intel_soc_pmic *pmic;
int ret;
pmic = devm_kzalloc(dev, sizeof(*pmic), GFP_KERNEL);
if (!pmic)
return -ENOMEM;
i2c_set_clientdata(i2c, pmic);
pmic->regmap = devm_regmap_init_i2c(i2c, &chtdc_ti_regmap_config);
if (IS_ERR(pmic->regmap))
return PTR_ERR(pmic->regmap);
pmic->irq = i2c->irq;
ret = devm_regmap_add_irq_chip(dev, pmic->regmap, pmic->irq,
IRQF_ONESHOT, 0,
&chtdc_ti_irq_chip,
&pmic->irq_chip_data);
if (ret)
return ret;
return devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, chtdc_ti_dev,
ARRAY_SIZE(chtdc_ti_dev), NULL, 0,
regmap_irq_get_domain(pmic->irq_chip_data));
}
static void chtdc_ti_shutdown(struct i2c_client *i2c)
{
struct intel_soc_pmic *pmic = i2c_get_clientdata(i2c);
disable_irq(pmic->irq);
}
static int __maybe_unused chtdc_ti_suspend(struct device *dev)
{
struct intel_soc_pmic *pmic = dev_get_drvdata(dev);
disable_irq(pmic->irq);
return 0;
}
static int __maybe_unused chtdc_ti_resume(struct device *dev)
{
struct intel_soc_pmic *pmic = dev_get_drvdata(dev);
enable_irq(pmic->irq);
return 0;
}
static SIMPLE_DEV_PM_OPS(chtdc_ti_pm_ops, chtdc_ti_suspend, chtdc_ti_resume);
static const struct acpi_device_id chtdc_ti_acpi_ids[] = {
{ "INT33F5" },
{ },
};
MODULE_DEVICE_TABLE(acpi, chtdc_ti_acpi_ids);
static struct i2c_driver chtdc_ti_i2c_driver = {
.driver = {
.name = "intel_soc_pmic_chtdc_ti",
.pm = &chtdc_ti_pm_ops,
.acpi_match_table = chtdc_ti_acpi_ids,
},
.probe_new = chtdc_ti_probe,
.shutdown = chtdc_ti_shutdown,
};
module_i2c_driver(chtdc_ti_i2c_driver);
MODULE_DESCRIPTION("I2C driver for Intel SoC Dollar Cove TI PMIC");
MODULE_LICENSE("GPL v2");

查看文件

@@ -522,6 +522,7 @@ static struct lpc_ich_info lpc_chipset_info[] = {
.name = "Avoton SoC",
.iTCO_version = 3,
.gpio_version = AVOTON_GPIO,
.spi_type = INTEL_SPI_BYT,
},
[LPC_BAYTRAIL] = {
.name = "Bay Trail SoC",

查看文件

@@ -48,7 +48,10 @@ static const struct mfd_cell max77693_devs[] = {
.name = "max77693-charger",
.of_compatible = "maxim,max77693-charger",
},
{ .name = "max77693-muic", },
{
.name = "max77693-muic",
.of_compatible = "maxim,max77693-muic",
},
{
.name = "max77693-haptic",
.of_compatible = "maxim,max77693-haptic",

查看文件

@@ -196,8 +196,10 @@ static int mxs_lradc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, lradc);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENOMEM;
if (!res) {
ret = -ENOMEM;
goto err_clk;
}
switch (lradc->soc) {
case IMX23_LRADC:

查看文件

@@ -103,8 +103,64 @@ static void rtsx_base_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
rtsx_pci_write_register(pcr, FPDCTL, 0x03, 0x03);
}
static void rts5249_init_from_cfg(struct rtsx_pcr *pcr)
{
struct rtsx_cr_option *option = &(pcr->option);
u32 lval;
if (CHK_PCI_PID(pcr, PID_524A))
rtsx_pci_read_config_dword(pcr,
PCR_ASPM_SETTING_REG1, &lval);
else
rtsx_pci_read_config_dword(pcr,
PCR_ASPM_SETTING_REG2, &lval);
if (lval & ASPM_L1_1_EN_MASK)
rtsx_set_dev_flag(pcr, ASPM_L1_1_EN);
if (lval & ASPM_L1_2_EN_MASK)
rtsx_set_dev_flag(pcr, ASPM_L1_2_EN);
if (lval & PM_L1_1_EN_MASK)
rtsx_set_dev_flag(pcr, PM_L1_1_EN);
if (lval & PM_L1_2_EN_MASK)
rtsx_set_dev_flag(pcr, PM_L1_2_EN);
if (option->ltr_en) {
u16 val;
pcie_capability_read_word(pcr->pci, PCI_EXP_DEVCTL2, &val);
if (val & PCI_EXP_DEVCTL2_LTR_EN) {
option->ltr_enabled = true;
option->ltr_active = true;
rtsx_set_ltr_latency(pcr, option->ltr_active_latency);
} else {
option->ltr_enabled = false;
}
}
}
static int rts5249_init_from_hw(struct rtsx_pcr *pcr)
{
struct rtsx_cr_option *option = &(pcr->option);
if (rtsx_check_dev_flag(pcr, ASPM_L1_1_EN | ASPM_L1_2_EN
| PM_L1_1_EN | PM_L1_2_EN))
option->force_clkreq_0 = false;
else
option->force_clkreq_0 = true;
return 0;
}
static int rts5249_extra_init_hw(struct rtsx_pcr *pcr)
{
struct rtsx_cr_option *option = &(pcr->option);
rts5249_init_from_cfg(pcr);
rts5249_init_from_hw(pcr);
rtsx_pci_init_cmd(pcr);
/* Rest L1SUB Config */
@@ -125,7 +181,18 @@ static int rts5249_extra_init_hw(struct rtsx_pcr *pcr)
else
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG, 0xB0, 0x80);
return rtsx_pci_send_cmd(pcr, 100);
/*
* If u_force_clkreq_0 is enabled, CLKREQ# PIN will be forced
* to drive low, and we forcibly request clock.
*/
if (option->force_clkreq_0)
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG,
FORCE_CLKREQ_DELINK_MASK, FORCE_CLKREQ_LOW);
else
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG,
FORCE_CLKREQ_DELINK_MASK, FORCE_CLKREQ_HIGH);
return rtsx_pci_send_cmd(pcr, CMD_TIMEOUT_DEF);
}
static int rts5249_optimize_phy(struct rtsx_pcr *pcr)
@@ -285,6 +352,31 @@ static int rtsx_base_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
return rtsx_pci_send_cmd(pcr, 100);
}
static void rts5249_set_aspm(struct rtsx_pcr *pcr, bool enable)
{
struct rtsx_cr_option *option = &pcr->option;
u8 val = 0;
if (pcr->aspm_enabled == enable)
return;
if (option->dev_aspm_mode == DEV_ASPM_DYNAMIC) {
if (enable)
val = pcr->aspm_en;
rtsx_pci_update_cfg_byte(pcr,
pcr->pcie_cap + PCI_EXP_LNKCTL,
ASPM_MASK_NEG, val);
} else if (option->dev_aspm_mode == DEV_ASPM_BACKDOOR) {
u8 mask = FORCE_ASPM_VAL_MASK | FORCE_ASPM_CTL0;
if (!enable)
val = FORCE_ASPM_CTL0;
rtsx_pci_write_register(pcr, ASPM_FORCE_CTL, mask, val);
}
pcr->aspm_enabled = enable;
}
static const struct pcr_ops rts5249_pcr_ops = {
.fetch_vendor_settings = rtsx_base_fetch_vendor_settings,
.extra_init_hw = rts5249_extra_init_hw,
@@ -297,6 +389,7 @@ static const struct pcr_ops rts5249_pcr_ops = {
.card_power_off = rtsx_base_card_power_off,
.switch_output_voltage = rtsx_base_switch_output_voltage,
.force_power_down = rtsx_base_force_power_down,
.set_aspm = rts5249_set_aspm,
};
/* SD Pull Control Enable:
@@ -353,6 +446,8 @@ static const u32 rts5249_ms_pull_ctl_disable_tbl[] = {
void rts5249_init_params(struct rtsx_pcr *pcr)
{
struct rtsx_cr_option *option = &(pcr->option);
pcr->extra_caps = EXTRA_CAPS_SD_SDR50 | EXTRA_CAPS_SD_SDR104;
pcr->num_slots = 2;
pcr->ops = &rts5249_pcr_ops;
@@ -372,6 +467,20 @@ void rts5249_init_params(struct rtsx_pcr *pcr)
pcr->ms_pull_ctl_disable_tbl = rts5249_ms_pull_ctl_disable_tbl;
pcr->reg_pm_ctrl3 = PM_CTRL3;
option->dev_flags = (LTR_L1SS_PWR_GATE_CHECK_CARD_EN
| LTR_L1SS_PWR_GATE_EN);
option->ltr_en = true;
/* Init latency of active, idle, L1OFF to 60us, 300us, 3ms */
option->ltr_active_latency = LTR_ACTIVE_LATENCY_DEF;
option->ltr_idle_latency = LTR_IDLE_LATENCY_DEF;
option->ltr_l1off_latency = LTR_L1OFF_LATENCY_DEF;
option->dev_aspm_mode = DEV_ASPM_DYNAMIC;
option->l1_snooze_delay = L1_SNOOZE_DELAY_DEF;
option->ltr_l1off_sspwrgate = LTR_L1OFF_SSPWRGATE_5249_DEF;
option->ltr_l1off_snooze_sspwrgate =
LTR_L1OFF_SNOOZE_SSPWRGATE_5249_DEF;
}
static int rts524a_write_phy(struct rtsx_pcr *pcr, u8 addr, u16 val)
@@ -459,6 +568,40 @@ static int rts524a_extra_init_hw(struct rtsx_pcr *pcr)
return 0;
}
static void rts5250_set_l1off_cfg_sub_d0(struct rtsx_pcr *pcr, int active)
{
struct rtsx_cr_option *option = &(pcr->option);
u32 interrupt = rtsx_pci_readl(pcr, RTSX_BIPR);
int card_exist = (interrupt & SD_EXIST) | (interrupt & MS_EXIST);
int aspm_L1_1, aspm_L1_2;
u8 val = 0;
aspm_L1_1 = rtsx_check_dev_flag(pcr, ASPM_L1_1_EN);
aspm_L1_2 = rtsx_check_dev_flag(pcr, ASPM_L1_2_EN);
if (active) {
/* Run, latency: 60us */
if (aspm_L1_1)
val = option->ltr_l1off_snooze_sspwrgate;
} else {
/* L1off, latency: 300us */
if (aspm_L1_2)
val = option->ltr_l1off_sspwrgate;
}
if (aspm_L1_1 || aspm_L1_2) {
if (rtsx_check_dev_flag(pcr,
LTR_L1SS_PWR_GATE_CHECK_CARD_EN)) {
if (card_exist)
val &= ~L1OFF_MBIAS2_EN_5250;
else
val |= L1OFF_MBIAS2_EN_5250;
}
}
rtsx_set_l1off_sub(pcr, val);
}
static const struct pcr_ops rts524a_pcr_ops = {
.write_phy = rts524a_write_phy,
.read_phy = rts524a_read_phy,
@@ -473,11 +616,16 @@ static const struct pcr_ops rts524a_pcr_ops = {
.card_power_off = rtsx_base_card_power_off,
.switch_output_voltage = rtsx_base_switch_output_voltage,
.force_power_down = rtsx_base_force_power_down,
.set_l1off_cfg_sub_d0 = rts5250_set_l1off_cfg_sub_d0,
.set_aspm = rts5249_set_aspm,
};
void rts524a_init_params(struct rtsx_pcr *pcr)
{
rts5249_init_params(pcr);
pcr->option.ltr_l1off_sspwrgate = LTR_L1OFF_SSPWRGATE_5250_DEF;
pcr->option.ltr_l1off_snooze_sspwrgate =
LTR_L1OFF_SNOOZE_SSPWRGATE_5250_DEF;
pcr->reg_pm_ctrl3 = RTS524A_PM_CTRL3;
pcr->ops = &rts524a_pcr_ops;
@@ -576,11 +724,16 @@ static const struct pcr_ops rts525a_pcr_ops = {
.card_power_off = rtsx_base_card_power_off,
.switch_output_voltage = rts525a_switch_output_voltage,
.force_power_down = rtsx_base_force_power_down,
.set_l1off_cfg_sub_d0 = rts5250_set_l1off_cfg_sub_d0,
.set_aspm = rts5249_set_aspm,
};
void rts525a_init_params(struct rtsx_pcr *pcr)
{
rts5249_init_params(pcr);
pcr->option.ltr_l1off_sspwrgate = LTR_L1OFF_SSPWRGATE_5250_DEF;
pcr->option.ltr_l1off_snooze_sspwrgate =
LTR_L1OFF_SNOOZE_SSPWRGATE_5250_DEF;
pcr->reg_pm_ctrl3 = RTS524A_PM_CTRL3;
pcr->ops = &rts525a_pcr_ops;

查看文件

@@ -79,6 +79,96 @@ static inline void rtsx_pci_disable_aspm(struct rtsx_pcr *pcr)
0xFC, 0);
}
int rtsx_comm_set_ltr_latency(struct rtsx_pcr *pcr, u32 latency)
{
rtsx_pci_write_register(pcr, MSGTXDATA0,
MASK_8_BIT_DEF, (u8) (latency & 0xFF));
rtsx_pci_write_register(pcr, MSGTXDATA1,
MASK_8_BIT_DEF, (u8)((latency >> 8) & 0xFF));
rtsx_pci_write_register(pcr, MSGTXDATA2,
MASK_8_BIT_DEF, (u8)((latency >> 16) & 0xFF));
rtsx_pci_write_register(pcr, MSGTXDATA3,
MASK_8_BIT_DEF, (u8)((latency >> 24) & 0xFF));
rtsx_pci_write_register(pcr, LTR_CTL, LTR_TX_EN_MASK |
LTR_LATENCY_MODE_MASK, LTR_TX_EN_1 | LTR_LATENCY_MODE_SW);
return 0;
}
int rtsx_set_ltr_latency(struct rtsx_pcr *pcr, u32 latency)
{
if (pcr->ops->set_ltr_latency)
return pcr->ops->set_ltr_latency(pcr, latency);
else
return rtsx_comm_set_ltr_latency(pcr, latency);
}
static void rtsx_comm_set_aspm(struct rtsx_pcr *pcr, bool enable)
{
struct rtsx_cr_option *option = &pcr->option;
if (pcr->aspm_enabled == enable)
return;
if (option->dev_aspm_mode == DEV_ASPM_DYNAMIC) {
if (enable)
rtsx_pci_enable_aspm(pcr);
else
rtsx_pci_disable_aspm(pcr);
} else if (option->dev_aspm_mode == DEV_ASPM_BACKDOOR) {
u8 mask = FORCE_ASPM_VAL_MASK;
u8 val = 0;
if (enable)
val = pcr->aspm_en;
rtsx_pci_write_register(pcr, ASPM_FORCE_CTL, mask, val);
}
pcr->aspm_enabled = enable;
}
static void rtsx_disable_aspm(struct rtsx_pcr *pcr)
{
if (pcr->ops->set_aspm)
pcr->ops->set_aspm(pcr, false);
else
rtsx_comm_set_aspm(pcr, false);
}
int rtsx_set_l1off_sub(struct rtsx_pcr *pcr, u8 val)
{
rtsx_pci_write_register(pcr, L1SUB_CONFIG3, 0xFF, val);
return 0;
}
void rtsx_set_l1off_sub_cfg_d0(struct rtsx_pcr *pcr, int active)
{
if (pcr->ops->set_l1off_cfg_sub_d0)
pcr->ops->set_l1off_cfg_sub_d0(pcr, active);
}
static void rtsx_comm_pm_full_on(struct rtsx_pcr *pcr)
{
struct rtsx_cr_option *option = &pcr->option;
rtsx_disable_aspm(pcr);
if (option->ltr_enabled)
rtsx_set_ltr_latency(pcr, option->ltr_active_latency);
if (rtsx_check_dev_flag(pcr, LTR_L1SS_PWR_GATE_EN))
rtsx_set_l1off_sub_cfg_d0(pcr, 1);
}
void rtsx_pm_full_on(struct rtsx_pcr *pcr)
{
if (pcr->ops->full_on)
pcr->ops->full_on(pcr);
else
rtsx_comm_pm_full_on(pcr);
}
void rtsx_pci_start_run(struct rtsx_pcr *pcr)
{
/* If pci device removed, don't queue idle work any more */
@@ -89,9 +179,7 @@ void rtsx_pci_start_run(struct rtsx_pcr *pcr)
pcr->state = PDEV_STAT_RUN;
if (pcr->ops->enable_auto_blink)
pcr->ops->enable_auto_blink(pcr);
if (pcr->aspm_en)
rtsx_pci_disable_aspm(pcr);
rtsx_pm_full_on(pcr);
}
mod_delayed_work(system_wq, &pcr->idle_work, msecs_to_jiffies(200));
@@ -958,6 +1046,41 @@ static int rtsx_pci_acquire_irq(struct rtsx_pcr *pcr)
return 0;
}
static void rtsx_enable_aspm(struct rtsx_pcr *pcr)
{
if (pcr->ops->set_aspm)
pcr->ops->set_aspm(pcr, true);
else
rtsx_comm_set_aspm(pcr, true);
}
static void rtsx_comm_pm_power_saving(struct rtsx_pcr *pcr)
{
struct rtsx_cr_option *option = &pcr->option;
if (option->ltr_enabled) {
u32 latency = option->ltr_l1off_latency;
if (rtsx_check_dev_flag(pcr, L1_SNOOZE_TEST_EN))
mdelay(option->l1_snooze_delay);
rtsx_set_ltr_latency(pcr, latency);
}
if (rtsx_check_dev_flag(pcr, LTR_L1SS_PWR_GATE_EN))
rtsx_set_l1off_sub_cfg_d0(pcr, 0);
rtsx_enable_aspm(pcr);
}
void rtsx_pm_power_saving(struct rtsx_pcr *pcr)
{
if (pcr->ops->power_saving)
pcr->ops->power_saving(pcr);
else
rtsx_comm_pm_power_saving(pcr);
}
static void rtsx_pci_idle_work(struct work_struct *work)
{
struct delayed_work *dwork = to_delayed_work(work);
@@ -974,8 +1097,7 @@ static void rtsx_pci_idle_work(struct work_struct *work)
if (pcr->ops->turn_off_led)
pcr->ops->turn_off_led(pcr);
if (pcr->aspm_en)
rtsx_pci_enable_aspm(pcr);
rtsx_pm_power_saving(pcr);
mutex_unlock(&pcr->pcr_mutex);
}
@@ -1063,6 +1185,16 @@ static int rtsx_pci_init_hw(struct rtsx_pcr *pcr)
if (err < 0)
return err;
switch (PCI_PID(pcr)) {
case PID_5250:
case PID_524A:
case PID_525A:
rtsx_pci_write_register(pcr, PM_CLK_FORCE_CTL, 1, 1);
break;
default:
break;
}
/* Enable clk_request_n to enable clock power management */
rtsx_pci_write_config_byte(pcr, pcr->pcie_cap + PCI_EXP_LNKCTL + 1, 1);
/* Enter L1 when host tx idle */

查看文件

@@ -32,6 +32,18 @@
#define RTS524A_PME_FORCE_CTL 0xFF78
#define RTS524A_PM_CTRL3 0xFF7E
#define LTR_ACTIVE_LATENCY_DEF 0x883C
#define LTR_IDLE_LATENCY_DEF 0x892C
#define LTR_L1OFF_LATENCY_DEF 0x9003
#define L1_SNOOZE_DELAY_DEF 1
#define LTR_L1OFF_SSPWRGATE_5249_DEF 0xAF
#define LTR_L1OFF_SSPWRGATE_5250_DEF 0xFF
#define LTR_L1OFF_SNOOZE_SSPWRGATE_5249_DEF 0xAC
#define LTR_L1OFF_SNOOZE_SSPWRGATE_5250_DEF 0xF8
#define CMD_TIMEOUT_DEF 100
#define ASPM_MASK_NEG 0xFC
#define MASK_8_BIT_DEF 0xFF
int __rtsx_pci_write_phy_register(struct rtsx_pcr *pcr, u8 addr, u16 val);
int __rtsx_pci_read_phy_register(struct rtsx_pcr *pcr, u8 addr, u16 *val);
@@ -85,5 +97,7 @@ do { \
/* generic operations */
int rtsx_gops_pm_reset(struct rtsx_pcr *pcr);
int rtsx_set_ltr_latency(struct rtsx_pcr *pcr, u32 latency);
int rtsx_set_l1off_sub(struct rtsx_pcr *pcr, u8 val);
#endif

查看文件

@@ -0,0 +1,259 @@
/*
* Copyright (C) 2017 Spreadtrum Communications Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mfd/core.h>
#include <linux/of_device.h>
#include <linux/regmap.h>
#include <linux/spi/spi.h>
#define SPRD_PMIC_INT_MASK_STATUS 0x0
#define SPRD_PMIC_INT_RAW_STATUS 0x4
#define SPRD_PMIC_INT_EN 0x8
#define SPRD_SC2731_IRQ_BASE 0x140
#define SPRD_SC2731_IRQ_NUMS 16
struct sprd_pmic {
struct regmap *regmap;
struct device *dev;
struct regmap_irq *irqs;
struct regmap_irq_chip irq_chip;
struct regmap_irq_chip_data *irq_data;
int irq;
};
struct sprd_pmic_data {
u32 irq_base;
u32 num_irqs;
};
/*
* Since different PMICs of SC27xx series can have different interrupt
* base address and irq number, we should save irq number and irq base
* in the device data structure.
*/
static const struct sprd_pmic_data sc2731_data = {
.irq_base = SPRD_SC2731_IRQ_BASE,
.num_irqs = SPRD_SC2731_IRQ_NUMS,
};
static const struct mfd_cell sprd_pmic_devs[] = {
{
.name = "sc27xx-wdt",
.of_compatible = "sprd,sc27xx-wdt",
}, {
.name = "sc27xx-rtc",
.of_compatible = "sprd,sc27xx-rtc",
}, {
.name = "sc27xx-charger",
.of_compatible = "sprd,sc27xx-charger",
}, {
.name = "sc27xx-chg-timer",
.of_compatible = "sprd,sc27xx-chg-timer",
}, {
.name = "sc27xx-fast-chg",
.of_compatible = "sprd,sc27xx-fast-chg",
}, {
.name = "sc27xx-chg-wdt",
.of_compatible = "sprd,sc27xx-chg-wdt",
}, {
.name = "sc27xx-typec",
.of_compatible = "sprd,sc27xx-typec",
}, {
.name = "sc27xx-flash",
.of_compatible = "sprd,sc27xx-flash",
}, {
.name = "sc27xx-eic",
.of_compatible = "sprd,sc27xx-eic",
}, {
.name = "sc27xx-efuse",
.of_compatible = "sprd,sc27xx-efuse",
}, {
.name = "sc27xx-thermal",
.of_compatible = "sprd,sc27xx-thermal",
}, {
.name = "sc27xx-adc",
.of_compatible = "sprd,sc27xx-adc",
}, {
.name = "sc27xx-audio-codec",
.of_compatible = "sprd,sc27xx-audio-codec",
}, {
.name = "sc27xx-regulator",
.of_compatible = "sprd,sc27xx-regulator",
}, {
.name = "sc27xx-vibrator",
.of_compatible = "sprd,sc27xx-vibrator",
}, {
.name = "sc27xx-keypad-led",
.of_compatible = "sprd,sc27xx-keypad-led",
}, {
.name = "sc27xx-bltc",
.of_compatible = "sprd,sc27xx-bltc",
}, {
.name = "sc27xx-fgu",
.of_compatible = "sprd,sc27xx-fgu",
}, {
.name = "sc27xx-7sreset",
.of_compatible = "sprd,sc27xx-7sreset",
}, {
.name = "sc27xx-poweroff",
.of_compatible = "sprd,sc27xx-poweroff",
},
};
static int sprd_pmic_spi_write(void *context, const void *data, size_t count)
{
struct device *dev = context;
struct spi_device *spi = to_spi_device(dev);
return spi_write(spi, data, count);
}
static int sprd_pmic_spi_read(void *context,
const void *reg, size_t reg_size,
void *val, size_t val_size)
{
struct device *dev = context;
struct spi_device *spi = to_spi_device(dev);
u32 rx_buf[2] = { 0 };
int ret;
/* Now we only support one PMIC register to read every time. */
if (reg_size != sizeof(u32) || val_size != sizeof(u32))
return -EINVAL;
/* Copy address to read from into first element of SPI buffer. */
memcpy(rx_buf, reg, sizeof(u32));
ret = spi_read(spi, rx_buf, 1);
if (ret < 0)
return ret;
memcpy(val, rx_buf, val_size);
return 0;
}
static struct regmap_bus sprd_pmic_regmap = {
.write = sprd_pmic_spi_write,
.read = sprd_pmic_spi_read,
.reg_format_endian_default = REGMAP_ENDIAN_NATIVE,
.val_format_endian_default = REGMAP_ENDIAN_NATIVE,
};
static const struct regmap_config sprd_pmic_config = {
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
.max_register = 0xffff,
};
static int sprd_pmic_probe(struct spi_device *spi)
{
struct sprd_pmic *ddata;
const struct sprd_pmic_data *pdata;
int ret, i;
pdata = of_device_get_match_data(&spi->dev);
if (!pdata) {
dev_err(&spi->dev, "No matching driver data found\n");
return -EINVAL;
}
ddata = devm_kzalloc(&spi->dev, sizeof(*ddata), GFP_KERNEL);
if (!ddata)
return -ENOMEM;
ddata->regmap = devm_regmap_init(&spi->dev, &sprd_pmic_regmap,
&spi->dev, &sprd_pmic_config);
if (IS_ERR(ddata->regmap)) {
ret = PTR_ERR(ddata->regmap);
dev_err(&spi->dev, "Failed to allocate register map %d\n", ret);
return ret;
}
spi_set_drvdata(spi, ddata);
ddata->dev = &spi->dev;
ddata->irq = spi->irq;
ddata->irq_chip.name = dev_name(&spi->dev);
ddata->irq_chip.status_base =
pdata->irq_base + SPRD_PMIC_INT_MASK_STATUS;
ddata->irq_chip.mask_base = pdata->irq_base + SPRD_PMIC_INT_EN;
ddata->irq_chip.ack_base = 0;
ddata->irq_chip.num_regs = 1;
ddata->irq_chip.num_irqs = pdata->num_irqs;
ddata->irq_chip.mask_invert = true;
ddata->irqs = devm_kzalloc(&spi->dev, sizeof(struct regmap_irq) *
pdata->num_irqs, GFP_KERNEL);
if (!ddata->irqs)
return -ENOMEM;
ddata->irq_chip.irqs = ddata->irqs;
for (i = 0; i < pdata->num_irqs; i++) {
ddata->irqs[i].reg_offset = i / pdata->num_irqs;
ddata->irqs[i].mask = BIT(i % pdata->num_irqs);
}
ret = devm_regmap_add_irq_chip(&spi->dev, ddata->regmap, ddata->irq,
IRQF_ONESHOT | IRQF_NO_SUSPEND, 0,
&ddata->irq_chip, &ddata->irq_data);
if (ret) {
dev_err(&spi->dev, "Failed to add PMIC irq chip %d\n", ret);
return ret;
}
ret = devm_mfd_add_devices(&spi->dev, PLATFORM_DEVID_AUTO,
sprd_pmic_devs, ARRAY_SIZE(sprd_pmic_devs),
NULL, 0,
regmap_irq_get_domain(ddata->irq_data));
if (ret) {
dev_err(&spi->dev, "Failed to register device %d\n", ret);
return ret;
}
return 0;
}
static const struct of_device_id sprd_pmic_match[] = {
{ .compatible = "sprd,sc2731", .data = &sc2731_data },
{},
};
MODULE_DEVICE_TABLE(of, sprd_pmic_match);
static struct spi_driver sprd_pmic_driver = {
.driver = {
.name = "sc27xx-pmic",
.bus = &spi_bus_type,
.of_match_table = sprd_pmic_match,
},
.probe = sprd_pmic_probe,
};
static int __init sprd_pmic_init(void)
{
return spi_register_driver(&sprd_pmic_driver);
}
subsys_initcall(sprd_pmic_init);
static void __exit sprd_pmic_exit(void)
{
spi_unregister_driver(&sprd_pmic_driver);
}
module_exit(sprd_pmic_exit);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Spreadtrum SC27xx PMICs driver");
MODULE_AUTHOR("Baolin Wang <baolin.wang@spreadtrum.com>");

查看文件

@@ -314,7 +314,7 @@ static int ssbi_probe(struct platform_device *pdev)
spin_lock_init(&ssbi->lock);
return of_platform_populate(np, NULL, NULL, &pdev->dev);
return devm_of_platform_populate(&pdev->dev);
}
static const struct of_device_id ssbi_match_table[] = {

查看文件

@@ -72,10 +72,12 @@ static int stw481x_get_pctl_reg(struct stw481x *stw481x, u8 reg)
static int stw481x_startup(struct stw481x *stw481x)
{
/* Voltages multiplied by 100 */
u8 vcore_val[] = { 100, 105, 110, 115, 120, 122, 124, 126, 128,
130, 132, 134, 136, 138, 140, 145 };
u8 vpll_val[] = { 105, 120, 130, 180 };
u8 vaux_val[] = { 15, 18, 25, 28 };
static const u8 vcore_val[] = {
100, 105, 110, 115, 120, 122, 124, 126, 128,
130, 132, 134, 136, 138, 140, 145
};
static const u8 vpll_val[] = { 105, 120, 130, 180 };
static const u8 vaux_val[] = { 15, 18, 25, 28 };
u8 vcore;
u8 vcore_slp;
u8 vpll;

查看文件

@@ -311,37 +311,20 @@ static const struct regmap_config tps65217_regmap_config = {
};
static const struct of_device_id tps65217_of_match[] = {
{ .compatible = "ti,tps65217", .data = (void *)TPS65217 },
{ .compatible = "ti,tps65217"},
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, tps65217_of_match);
static int tps65217_probe(struct i2c_client *client,
const struct i2c_device_id *ids)
static int tps65217_probe(struct i2c_client *client)
{
struct tps65217 *tps;
unsigned int version;
unsigned long chip_id = ids->driver_data;
const struct of_device_id *match;
bool status_off = false;
int ret;
if (client->dev.of_node) {
match = of_match_device(tps65217_of_match, &client->dev);
if (!match) {
dev_err(&client->dev,
"Failed to find matching dt id\n");
return -EINVAL;
}
chip_id = (unsigned long)match->data;
status_off = of_property_read_bool(client->dev.of_node,
"ti,pmic-shutdown-controller");
}
if (!chip_id) {
dev_err(&client->dev, "id is null.\n");
return -ENODEV;
}
status_off = of_property_read_bool(client->dev.of_node,
"ti,pmic-shutdown-controller");
tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL);
if (!tps)
@@ -349,7 +332,6 @@ static int tps65217_probe(struct i2c_client *client,
i2c_set_clientdata(client, tps);
tps->dev = &client->dev;
tps->id = chip_id;
tps->regmap = devm_regmap_init_i2c(client, &tps65217_regmap_config);
if (IS_ERR(tps->regmap)) {
@@ -430,7 +412,7 @@ static struct i2c_driver tps65217_driver = {
.of_match_table = tps65217_of_match,
},
.id_table = tps65217_id_table,
.probe = tps65217_probe,
.probe_new = tps65217_probe,
.remove = tps65217_remove,
};

查看文件

@@ -215,17 +215,9 @@ static int tps65218_probe(struct i2c_client *client,
const struct i2c_device_id *ids)
{
struct tps65218 *tps;
const struct of_device_id *match;
int ret;
unsigned int chipid;
match = of_match_device(of_tps65218_match_table, &client->dev);
if (!match) {
dev_err(&client->dev,
"Failed to find matching dt id\n");
return -EINVAL;
}
tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL);
if (!tps)
return -ENOMEM;