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 ...
这个提交包含在:
@@ -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
|
||||
|
259
drivers/mfd/sprd-sc27xx-spi.c
普通文件
259
drivers/mfd/sprd-sc27xx-spi.c
普通文件
@@ -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;
|
||||
|
在新工单中引用
屏蔽一个用户