提交 d3092e4e 编写于 作者: L Linus Torvalds

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
  ...
......@@ -9,10 +9,16 @@ Required properties:
"aspeed,g5-scu", "syscon", "simple-mfd"
- reg: contains the offset and length of the SCU memory region
- #clock-cells: should be set to <1> - the system controller is also a
clock provider
- #reset-cells: should be set to <1> - the system controller is also a
reset line provider
Example:
syscon: syscon@1e6e2000 {
compatible = "aspeed,ast2400-scu", "syscon", "simple-mfd";
reg = <0x1e6e2000 0x1a8>;
#clock-cells = <1>;
#reset-cells = <1>;
};
Broadcom iProc Chip Device Resource Unit (CDRU)
Various Broadcom iProc SoCs have a set of registers that provide various
chip specific device and resource configurations. This node allows access to
these CDRU registers via syscon.
Required properties:
- compatible: should contain:
"brcm,sr-cdru", "syscon" for Stingray
- reg: base address and range of the CDRU registers
Example:
cdru: syscon@6641d000 {
compatible = "brcm,sr-cdru", "syscon";
reg = <0 0x6641d000 0 0x400>;
};
Broadcom iProc Multi Host Bridge (MHB)
Certain Broadcom iProc SoCs have a multi host bridge (MHB) block that controls
the connection and configuration of 1) internal PCIe serdes; 2) PCIe endpoint
interface; 3) access to the Nitro (network processing) engine
This node allows access to these MHB registers via syscon.
Required properties:
- compatible: should contain:
"brcm,sr-mhb", "syscon" for Stingray
- reg: base address and range of the MHB registers
Example:
mhb: syscon@60401000 {
compatible = "brcm,sr-mhb", "syscon";
reg = <0 0x60401000 0 0x38c>;
};
......@@ -127,6 +127,12 @@ Required properties for the LED child node:
Optional properties for the LED child node:
- label : see Documentation/devicetree/bindings/leds/common.txt
Optional nodes:
- max77693-muic :
Node used only by extcon consumers.
Required properties:
- compatible : "maxim,max77693-muic"
Example:
#include <dt-bindings/leds/common.h>
......
......@@ -113,7 +113,6 @@ MC13892 regulators:
Examples:
ecspi@70010000 { /* ECSPI1 */
fsl,spi-num-chipselects = <2>;
cs-gpios = <&gpio4 24 0>, /* GPIO4_24 */
<&gpio4 25 0>; /* GPIO4_25 */
......
Spreadtrum SC27xx Power Management Integrated Circuit (PMIC)
The Spreadtrum SC27xx series PMICs contain SC2720, SC2721, SC2723, SC2730
and SC2731. The Spreadtrum PMIC belonging to SC27xx series integrates all
mobile handset power management, audio codec, battery management and user
interface support function in a single chip. It has 6 major functional
blocks:
- DCDCs to support CPU, memory.
- LDOs to support both internal and external requirement.
- Battery management system, such as charger, fuel gauge.
- Audio codec.
- User interface function, such as indicator, flash LED and so on.
- IC level interface, such as power on/off control, RTC and typec and so on.
Required properties:
- compatible: Should be one of the following:
"sprd,sc2720"
"sprd,sc2721"
"sprd,sc2723"
"sprd,sc2730"
"sprd,sc2731"
- reg: The address of the device chip select, should be 0.
- spi-max-frequency: Typically set to 26000000.
- interrupts: The interrupt line the device is connected to.
- interrupt-controller: Marks the device node as an interrupt controller.
- #interrupt-cells: The number of cells to describe an PMIC IRQ, must be 2.
- #address-cells: Child device offset number of cells, must be 1.
- #size-cells: Child device size number of cells, must be 0.
Example:
pmic@0 {
compatible = "sprd,sc2731";
reg = <0>;
spi-max-frequency = <26000000>;
interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
interrupt-controller;
#interrupt-cells = <2>;
#address-cells = <1>;
#size-cells = <0>;
};
......@@ -4146,7 +4146,7 @@ F: Documentation/devicetree/bindings/mfd/da90*.txt
F: Documentation/devicetree/bindings/input/da90??-onkey.txt
F: Documentation/devicetree/bindings/thermal/da90??-thermal.txt
F: Documentation/devicetree/bindings/regulator/da92*.txt
F: Documentation/devicetree/bindings/watchdog/da92??-wdt.txt
F: Documentation/devicetree/bindings/watchdog/da90??-wdt.txt
F: Documentation/devicetree/bindings/sound/da[79]*.txt
F: drivers/gpio/gpio-da90??.c
F: drivers/hwmon/da90??-hwmon.c
......
......@@ -527,6 +527,12 @@ config CHT_WC_PMIC_OPREGION
help
This config adds ACPI operation region support for CHT Whiskey Cove PMIC.
config CHT_DC_TI_PMIC_OPREGION
bool "ACPI operation region support for Dollar Cove TI PMIC"
depends on INTEL_SOC_PMIC_CHTDC_TI
help
This config adds ACPI operation region support for Dollar Cove TI PMIC.
endif
config ACPI_CONFIGFS
......
......@@ -106,6 +106,7 @@ obj-$(CONFIG_CRC_PMIC_OPREGION) += pmic/intel_pmic_crc.o
obj-$(CONFIG_XPOWER_PMIC_OPREGION) += pmic/intel_pmic_xpower.o
obj-$(CONFIG_BXT_WC_PMIC_OPREGION) += pmic/intel_pmic_bxtwc.o
obj-$(CONFIG_CHT_WC_PMIC_OPREGION) += pmic/intel_pmic_chtwc.o
obj-$(CONFIG_CHT_DC_TI_PMIC_OPREGION) += pmic/intel_pmic_chtdc_ti.o
obj-$(CONFIG_ACPI_CONFIGFS) += acpi_configfs.o
......
/*
* Dollar Cove TI PMIC operation region driver
* Copyright (C) 2014 Intel Corporation. All rights reserved.
*
* Rewritten and cleaned up
* Copyright (C) 2017 Takashi Iwai <tiwai@suse.de>
*/
#include <linux/acpi.h>
#include <linux/init.h>
#include <linux/mfd/intel_soc_pmic.h>
#include <linux/platform_device.h>
#include "intel_pmic.h"
/* registers stored in 16bit BE (high:low, total 10bit) */
#define CHTDC_TI_VBAT 0x54
#define CHTDC_TI_DIETEMP 0x56
#define CHTDC_TI_BPTHERM 0x58
#define CHTDC_TI_GPADC 0x5a
static struct pmic_table chtdc_ti_power_table[] = {
{ .address = 0x00, .reg = 0x41 },
{ .address = 0x04, .reg = 0x42 },
{ .address = 0x08, .reg = 0x43 },
{ .address = 0x0c, .reg = 0x45 },
{ .address = 0x10, .reg = 0x46 },
{ .address = 0x14, .reg = 0x47 },
{ .address = 0x18, .reg = 0x48 },
{ .address = 0x1c, .reg = 0x49 },
{ .address = 0x20, .reg = 0x4a },
{ .address = 0x24, .reg = 0x4b },
{ .address = 0x28, .reg = 0x4c },
{ .address = 0x2c, .reg = 0x4d },
{ .address = 0x30, .reg = 0x4e },
};
static struct pmic_table chtdc_ti_thermal_table[] = {
{
.address = 0x00,
.reg = CHTDC_TI_GPADC
},
{
.address = 0x0c,
.reg = CHTDC_TI_GPADC
},
/* TMP2 -> SYSTEMP */
{
.address = 0x18,
.reg = CHTDC_TI_GPADC
},
/* TMP3 -> BPTHERM */
{
.address = 0x24,
.reg = CHTDC_TI_BPTHERM
},
{
.address = 0x30,
.reg = CHTDC_TI_GPADC
},
/* TMP5 -> DIETEMP */
{
.address = 0x3c,
.reg = CHTDC_TI_DIETEMP
},
};
static int chtdc_ti_pmic_get_power(struct regmap *regmap, int reg, int bit,
u64 *value)
{
int data;
if (regmap_read(regmap, reg, &data))
return -EIO;
*value = data & 1;
return 0;
}
static int chtdc_ti_pmic_update_power(struct regmap *regmap, int reg, int bit,
bool on)
{
return regmap_update_bits(regmap, reg, 1, on);
}
static int chtdc_ti_pmic_get_raw_temp(struct regmap *regmap, int reg)
{
u8 buf[2];
if (regmap_bulk_read(regmap, reg, buf, 2))
return -EIO;
/* stored in big-endian */
return ((buf[0] & 0x03) << 8) | buf[1];
}
static struct intel_pmic_opregion_data chtdc_ti_pmic_opregion_data = {
.get_power = chtdc_ti_pmic_get_power,
.update_power = chtdc_ti_pmic_update_power,
.get_raw_temp = chtdc_ti_pmic_get_raw_temp,
.power_table = chtdc_ti_power_table,
.power_table_count = ARRAY_SIZE(chtdc_ti_power_table),
.thermal_table = chtdc_ti_thermal_table,
.thermal_table_count = ARRAY_SIZE(chtdc_ti_thermal_table),
};
static int chtdc_ti_pmic_opregion_probe(struct platform_device *pdev)
{
struct intel_soc_pmic *pmic = dev_get_drvdata(pdev->dev.parent);
int err;
err = intel_pmic_install_opregion_handler(&pdev->dev,
ACPI_HANDLE(pdev->dev.parent), pmic->regmap,
&chtdc_ti_pmic_opregion_data);
if (err < 0)
return err;
/* Re-enumerate devices depending on PMIC */
acpi_walk_dep_device_list(ACPI_HANDLE(pdev->dev.parent));
return 0;
}
static const struct platform_device_id chtdc_ti_pmic_opregion_id_table[] = {
{ .name = "chtdc_ti_region" },
{},
};
static struct platform_driver chtdc_ti_pmic_opregion_driver = {
.probe = chtdc_ti_pmic_opregion_probe,
.driver = {
.name = "cht_dollar_cove_ti_pmic",
},
.id_table = chtdc_ti_pmic_opregion_id_table,
};
module_platform_driver(chtdc_ti_pmic_opregion_driver);
MODULE_DESCRIPTION("Dollar Cove TI PMIC opregion driver");
MODULE_LICENSE("GPL v2");
......@@ -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);
......
/*
* 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
/*
* 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;
......
......@@ -228,11 +228,6 @@ static int tps65217_regulator_probe(struct platform_device *pdev)
int i, ret;
unsigned int val;
if (tps65217_chip_id(tps) != TPS65217) {
dev_err(&pdev->dev, "Invalid tps chip version\n");
return -ENODEV;
}
/* Allocate memory for strobes */
tps->strobes = devm_kzalloc(&pdev->dev, sizeof(u8) *
TPS65217_NUM_REGULATOR, GFP_KERNEL);
......
......@@ -275,17 +275,9 @@ static int tps65217_bl_probe(struct platform_device *pdev)
struct tps65217_bl_pdata *pdata;
struct backlight_properties bl_props;
if (tps->dev->of_node) {
pdata = tps65217_bl_parse_dt(pdev);
if (IS_ERR(pdata))
return PTR_ERR(pdata);
} else {
pdata = dev_get_platdata(&pdev->dev);
if (!pdata) {
dev_err(&pdev->dev, "no platform data provided\n");
return -EINVAL;
}
}
pdata = tps65217_bl_parse_dt(pdev);
if (IS_ERR(pdata))
return PTR_ERR(pdata);
tps65217_bl = devm_kzalloc(&pdev->dev, sizeof(*tps65217_bl),
GFP_KERNEL);
......
......@@ -574,6 +574,12 @@
#define MSGTXDATA3 0xFE47
#define MSGTXCTL 0xFE48
#define LTR_CTL 0xFE4A
#define LTR_TX_EN_MASK BIT(7)
#define LTR_TX_EN_1 BIT(7)
#define LTR_TX_EN_0 0
#define LTR_LATENCY_MODE_MASK BIT(6)
#define LTR_LATENCY_MODE_HW 0
#define LTR_LATENCY_MODE_SW BIT(6)
#define OBFF_CFG 0xFE4C
#define CDRESUMECTL 0xFE52
......@@ -617,11 +623,15 @@
#define L1SUB_CONFIG2 0xFE8E
#define L1SUB_AUTO_CFG 0x02
#define L1SUB_CONFIG3 0xFE8F
#define L1OFF_MBIAS2_EN_5250 BIT(7)
#define DUMMY_REG_RESET_0 0xFE90
#define AUTOLOAD_CFG_BASE 0xFF00
#define PETXCFG 0xFF03
#define FORCE_CLKREQ_DELINK_MASK BIT(7)
#define FORCE_CLKREQ_LOW 0x80
#define FORCE_CLKREQ_HIGH 0x00
#define PM_CTRL1 0xFF44
#define CD_RESUME_EN_MASK 0xF0
......@@ -845,6 +855,9 @@
#define PHY_DIG1E_RX_EN_KEEP 0x0001
#define PHY_DUM_REG 0x1F
#define PCR_ASPM_SETTING_REG1 0x160
#define PCR_ASPM_SETTING_REG2 0x168
#define PCR_SETTING_REG1 0x724
#define PCR_SETTING_REG2 0x814
#define PCR_SETTING_REG3 0x747
......@@ -877,14 +890,79 @@ struct pcr_ops {
int (*conv_clk_and_div_n)(int clk, int dir);
void (*fetch_vendor_settings)(struct rtsx_pcr *pcr);
void (*force_power_down)(struct rtsx_pcr *pcr, u8 pm_state);
void (*set_aspm)(struct rtsx_pcr *pcr, bool enable);
int (*set_ltr_latency)(struct rtsx_pcr *pcr, u32 latency);
int (*set_l1off_sub)(struct rtsx_pcr *pcr, u8 val);
void (*set_l1off_cfg_sub_d0)(struct rtsx_pcr *pcr, int active);
void (*full_on)(struct rtsx_pcr *pcr);
void (*power_saving)(struct rtsx_pcr *pcr);
};
enum PDEV_STAT {PDEV_STAT_IDLE, PDEV_STAT_RUN};
#define ASPM_L1_1_EN_MASK BIT(3)
#define ASPM_L1_2_EN_MASK BIT(2)
#define PM_L1_1_EN_MASK BIT(1)
#define PM_L1_2_EN_MASK BIT(0)
#define ASPM_L1_1_EN BIT(0)
#define ASPM_L1_2_EN BIT(1)
#define PM_L1_1_EN BIT(2)
#define PM_L1_2_EN BIT(3)
#define LTR_L1SS_PWR_GATE_EN BIT(4)
#define L1_SNOOZE_TEST_EN BIT(5)
#define LTR_L1SS_PWR_GATE_CHECK_CARD_EN BIT(6)
enum dev_aspm_mode {
DEV_ASPM_DISABLE = 0,
DEV_ASPM_DYNAMIC,
DEV_ASPM_BACKDOOR,
DEV_ASPM_STATIC,
};
/*
* struct rtsx_cr_option - card reader option
* @dev_flags: device flags
* @force_clkreq_0: force clock request
* @ltr_en: enable ltr mode flag
* @ltr_enabled: ltr mode in configure space flag
* @ltr_active: ltr mode status
* @ltr_active_latency: ltr mode active latency
* @ltr_idle_latency: ltr mode idle latency
* @ltr_l1off_latency: ltr mode l1off latency
* @dev_aspm_mode: device aspm mode
* @l1_snooze_delay: l1 snooze delay
* @ltr_l1off_sspwrgate: ltr l1off sspwrgate
* @ltr_l1off_snooze_sspwrgate: ltr l1off snooze sspwrgate
*/
struct rtsx_cr_option {
u32 dev_flags;
bool force_clkreq_0;
bool ltr_en;
bool ltr_enabled;
bool ltr_active;
u32 ltr_active_latency;
u32 ltr_idle_latency;
u32 ltr_l1off_latency;
enum dev_aspm_mode dev_aspm_mode;
u32 l1_snooze_delay;
u8 ltr_l1off_sspwrgate;
u8 ltr_l1off_snooze_sspwrgate;
};
#define rtsx_set_dev_flag(cr, flag) \
((cr)->option.dev_flags |= (flag))
#define rtsx_clear_dev_flag(cr, flag) \
((cr)->option.dev_flags &= ~(flag))
#define rtsx_check_dev_flag(cr, flag) \
((cr)->option.dev_flags & (flag))
struct rtsx_pcr {
struct pci_dev *pci;
unsigned int id;
int pcie_cap;
struct rtsx_cr_option option;
/* pci resources */
unsigned long addr;
......@@ -941,6 +1019,7 @@ struct rtsx_pcr {
u8 card_drive_sel;
#define ASPM_L1_EN 0x02
u8 aspm_en;
bool aspm_enabled;
#define PCR_MS_PMOS (1 << 0)
#define PCR_REVERSE_SOCKET (1 << 1)
......@@ -965,6 +1044,11 @@ struct rtsx_pcr {
u8 dma_error_count;
};
#define PID_524A 0x524A
#define PID_5249 0x5249
#define PID_5250 0x5250
#define PID_525A 0x525A
#define CHK_PCI_PID(pcr, pid) ((pcr)->pci->device == (pid))
#define PCI_VID(pcr) ((pcr)->pci->vendor)
#define PCI_PID(pcr) ((pcr)->pci->device)
......
......@@ -263,7 +263,6 @@ struct tps65217_board {
struct tps65217 {
struct device *dev;
struct tps65217_board *pdata;
unsigned long id;
struct regulator_desc desc[TPS65217_NUM_REGULATOR];
struct regmap *regmap;
u8 *strobes;
......@@ -278,11 +277,6 @@ static inline struct tps65217 *dev_to_tps65217(struct device *dev)
return dev_get_drvdata(dev);
}
static inline unsigned long tps65217_chip_id(struct tps65217 *tps65217)
{
return tps65217->id;
}
int tps65217_reg_read(struct tps65217 *tps, unsigned int reg,
unsigned int *val);
int tps65217_reg_write(struct tps65217 *tps, unsigned int reg,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册