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

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

Pull MFD updates from Lee Jones:
 "New Drivers:
   - Add support for ROHM BD71828 PMICs and GPIOs
   - Add support for Qualcomm Aqstic Audio Codecs WCD9340 and WCD9341

  New Device Support:
   - Add support for BD71828 to BD70528 RTC driver
   - Add support for Intel's Jasper Lake to LPSS PCI

  New Functionality:
   - Add support for Power Key to ROHM BD71828
   - Add support for Clocks to ROHM BD71828
   - Add support for GPIOs to Dialog DA9062
   - Add support for USB PD Notify to ChromiumOS EC
   - Allow callers to specify args when requesting regmap lookup; syscon

  Fix-ups:
   - Improve error handling and sanity checking; atmel-hlcdc, dln2
   - Device Tree support/documentation; bd71828, da9062, xylon,logicvc,
     ab8500, max14577, atmel-usart
   - Match devices using platform IDs; bd7xxxx
   - Refactor BD718x7 regulator component; bd718x7-regulator
   - Use standard interfaces/helpers; syscon, sm501
   - Trivial (whitespace, spelling, etc); ab8500-core, Kconfig
   - Remove unused code; db8500-prcmu, tqmx86
   - Wait until boot has finished before accessing registers;
     madera-core
   - Provide missing register value defaults; cs47l15-tables
   - Allow more time for hardware to reset; madera-core

  Bug Fixes:
   - Fix erroneous register values; rohm-bd70528
   - Fix register volatility; axp20x, rn5t618
   - Fix Kconfig dependencies; MFD_MAX77650
   - Fix incorrect compatible string; da9062-core
   - Fix syscon_regmap_lookup_by_phandle_args() stub; syscon"

* tag 'mfd-next-5.6' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd: (41 commits)
  mfd: syscon: Fix syscon_regmap_lookup_by_phandle_args() dummy
  mfd: wcd934x: Add support to wcd9340/wcd9341 codec
  mfd: syscon: Add arguments support for syscon reference
  mfd: rn5t618: Mark ADC control register volatile
  dt-bindings: atmel-usart: Add microchip,sam9x60-{usart, dbgu}
  dt-bindings: atmel-usart: Remove wildcard
  mfd: cros_ec: Add cros-usbpd-notify subdevice
  mfd: da9062: Fix watchdog compatible string
  mfd: madera: Allow more time for hardware reset
  mfd: cs47l15: Add missing register default
  mfd: madera: Wait for boot done before accessing any other registers
  mfd: Kconfig: Rename Samsung to lowercase
  mfd: tqmx86: remove set but not used variable 'i2c_ien'
  mfd: dbx500-prcmu: Drop DSI pll clock functions
  mfd: dbx500-prcmu: Drop set_display_clocks()
  mfd: max77650: Select REGMAP_IRQ in Kconfig
  mfd: axp20x: Mark AXP20X_VBUS_IPSOUT_MGMT as volatile
  mfd: ab8500: Fix ab8500-clk typo
  mfd: intel-lpss: Add Intel Jasper Lake PCI IDs
  dt-bindings: mfd: max14577: Add reference to max14040_battery.txt descriptions
  ...
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/leds/rohm,bd71828-leds.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: ROHM BD71828 Power Management Integrated Circuit LED driver
maintainers:
- Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
description: |
This module is part of the ROHM BD71828 MFD device. For more details
see Documentation/devicetree/bindings/mfd/rohm,bd71828-pmic.yaml.
The LED controller is represented as a sub-node of the PMIC node on the device
tree.
The device has two LED outputs referred as GRNLED and AMBLED in data-sheet.
select: false
properties:
compatible:
const: rohm,bd71828-leds
patternProperties:
"^led-[1-2]$":
type: object
description:
Properties for a single LED.
properties:
#allOf:
#- $ref: "common.yaml#"
rohm,led-compatible:
description: LED identification string
allOf:
- $ref: "/schemas/types.yaml#/definitions/string"
- enum:
- bd71828-ambled
- bd71828-grnled
function:
description:
Purpose of LED as defined in dt-bindings/leds/common.h
$ref: "/schemas/types.yaml#/definitions/string"
color:
description:
LED colour as defined in dt-bindings/leds/common.h
$ref: "/schemas/types.yaml#/definitions/uint32"
required:
- compatible
* AB8500 Multi-Functional Device (MFD) * AB8500 Multi-Functional Device (MFD)
Required parent device properties: Required parent device properties:
- compatible : contains "stericsson,ab8500"; - compatible : contains "stericsson,ab8500" or "stericsson,ab8505";
- interrupts : contains the IRQ line for the AB8500 - interrupts : contains the IRQ line for the AB8500
- interrupt-controller : describes the AB8500 as an Interrupt Controller (has its own domain) - interrupt-controller : describes the AB8500 as an Interrupt Controller (has its own domain)
- #interrupt-cells : should be 2, for 2-cell format - #interrupt-cells : should be 2, for 2-cell format
...@@ -49,11 +49,13 @@ ab8500-charger : : vddadc : Charger interface ...@@ -49,11 +49,13 @@ ab8500-charger : : vddadc : Charger interface
: CH_WD_EXP : : Charger watchdog detected : CH_WD_EXP : : Charger watchdog detected
ab8500-gpadc : HW_CONV_END : vddadc : Analogue to Digital Converter ab8500-gpadc : HW_CONV_END : vddadc : Analogue to Digital Converter
SW_CONV_END : : SW_CONV_END : :
ab8500-gpio : : : GPIO Controller ab8500-gpio : : : GPIO Controller (AB8500)
ab8505-gpio : : : GPIO Controller (AB8505)
ab8500-ponkey : ONKEY_DBF : : Power-on Key ab8500-ponkey : ONKEY_DBF : : Power-on Key
ONKEY_DBR : : ONKEY_DBR : :
ab8500-pwm : : : Pulse Width Modulator ab8500-pwm : : : Pulse Width Modulator
ab8500-regulator : : : Regulators ab8500-regulator : : : Regulators (AB8500)
ab8505-regulator : : : Regulators (AB8505)
ab8500-rtc : 60S : : Real Time Clock ab8500-rtc : 60S : : Real Time Clock
: ALARM : : : ALARM : :
ab8500-sysctrl : : : System Control ab8500-sysctrl : : : System Control
......
* Atmel Universal Synchronous Asynchronous Receiver/Transmitter (USART) * Atmel Universal Synchronous Asynchronous Receiver/Transmitter (USART)
Required properties for USART: Required properties for USART:
- compatible: Should be "atmel,<chip>-usart" or "atmel,<chip>-dbgu" - compatible: Should be one of the following:
The compatible <chip> indicated will be the first SoC to support an - "atmel,at91rm9200-usart"
additional mode or an USART new feature. - "atmel,at91sam9260-usart"
For the dbgu UART, use "atmel,<chip>-dbgu", "atmel,<chip>-usart" - "microchip,sam9x60-usart"
- "atmel,at91rm9200-dbgu", "atmel,at91rm9200-usart"
- "atmel,at91sam9260-dbgu", "atmel,at91sam9260-usart"
- "microchip,sam9x60-dbgu", "microchip,sam9x60-usart"
- reg: Should contain registers location and length - reg: Should contain registers location and length
- interrupts: Should contain interrupt - interrupts: Should contain interrupt
- clock-names: tuple listing input clock names. - clock-names: tuple listing input clock names.
......
...@@ -13,6 +13,7 @@ da9062-rtc : : Real-Time Clock ...@@ -13,6 +13,7 @@ da9062-rtc : : Real-Time Clock
da9062-onkey : : On Key da9062-onkey : : On Key
da9062-watchdog : : Watchdog Timer da9062-watchdog : : Watchdog Timer
da9062-thermal : : Thermal da9062-thermal : : Thermal
da9062-gpio : : GPIOs
The DA9061 PMIC consists of: The DA9061 PMIC consists of:
...@@ -38,6 +39,15 @@ Required properties: ...@@ -38,6 +39,15 @@ Required properties:
See Documentation/devicetree/bindings/interrupt-controller/interrupts.txt for See Documentation/devicetree/bindings/interrupt-controller/interrupts.txt for
further information on IRQ bindings. further information on IRQ bindings.
Optional properties:
- gpio-controller : Marks the device as a gpio controller.
- #gpio-cells : Should be two. The first cell is the pin number and the
second cell is used to specify the gpio polarity.
See Documentation/devicetree/bindings/gpio/gpio.txt for further information on
GPIO bindings.
Sub-nodes: Sub-nodes:
- regulators : This node defines the settings for the LDOs and BUCKs. - regulators : This node defines the settings for the LDOs and BUCKs.
......
...@@ -5,6 +5,8 @@ Battery Charger and SFOUT LDO output for powering USB devices. It is ...@@ -5,6 +5,8 @@ Battery Charger and SFOUT LDO output for powering USB devices. It is
interfaced to host controller using I2C. interfaced to host controller using I2C.
MAX77836 additionally contains PMIC (with two LDO regulators) and Fuel Gauge. MAX77836 additionally contains PMIC (with two LDO regulators) and Fuel Gauge.
For the description of Fuel Gauge low SOC alert interrupt see:
../power/supply/max17040_battery.txt
Required properties: Required properties:
......
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/mfd/rohm,bd71828-pmic.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: ROHM BD71828 Power Management Integrated Circuit bindings
maintainers:
- Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
description: |
BD71828GW is a single-chip power management IC for battery-powered portable
devices. The IC integrates 7 buck converters, 7 LDOs, and a 1500 mA
single-cell linear charger. Also included is a Coulomb counter, a real-time
clock (RTC), and a 32.768 kHz clock gate.
properties:
compatible:
const: rohm,bd71828
reg:
description:
I2C slave address.
maxItems: 1
interrupts:
maxItems: 1
gpio-controller: true
"#gpio-cells":
const: 2
description: |
The first cell is the pin number and the second cell is used to specify
flags. See ../gpio/gpio.txt for more information.
clocks:
maxItems: 1
"#clock-cells":
const: 0
rohm,charger-sense-resistor-ohms:
minimum: 10000000
maximum: 50000000
description: |
BD71827 and BD71828 have SAR ADC for measuring charging currents.
External sense resistor (RSENSE in data sheet) should be used. If some
other but 30MOhm resistor is used the resistance value should be given
here in Ohms.
regulators:
$ref: ../regulator/rohm,bd71828-regulator.yaml
description:
List of child nodes that specify the regulators.
leds:
$ref: ../leds/rohm,bd71828-leds.yaml
gpio-reserved-ranges:
description: |
Usage of BD71828 GPIO pins can be changed via OTP. This property can be
used to mark the pins which should not be configured for GPIO. Please see
the ../gpio/gpio.txt for more information.
required:
- compatible
- reg
- interrupts
- clocks
- "#clock-cells"
- regulators
- gpio-controller
- "#gpio-cells"
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/leds/common.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
pmic: pmic@4b {
compatible = "rohm,bd71828";
reg = <0x4b>;
interrupt-parent = <&gpio1>;
interrupts = <29 IRQ_TYPE_LEVEL_LOW>;
clocks = <&osc 0>;
#clock-cells = <0>;
clock-output-names = "bd71828-32k-out";
gpio-controller;
#gpio-cells = <2>;
gpio-reserved-ranges = <0 1>, <2 1>;
rohm,charger-sense-resistor-ohms = <10000000>;
regulators {
buck1: BUCK1 {
regulator-name = "buck1";
regulator-min-microvolt = <500000>;
regulator-max-microvolt = <2000000>;
regulator-ramp-delay = <2500>;
};
buck2: BUCK2 {
regulator-name = "buck2";
regulator-min-microvolt = <500000>;
regulator-max-microvolt = <2000000>;
regulator-ramp-delay = <2500>;
};
buck3: BUCK3 {
regulator-name = "buck3";
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <2000000>;
};
buck4: BUCK4 {
regulator-name = "buck4";
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <1800000>;
};
buck5: BUCK5 {
regulator-name = "buck5";
regulator-min-microvolt = <2500000>;
regulator-max-microvolt = <3300000>;
};
buck6: BUCK6 {
regulator-name = "buck6";
regulator-min-microvolt = <500000>;
regulator-max-microvolt = <2000000>;
regulator-ramp-delay = <2500>;
};
buck7: BUCK7 {
regulator-name = "buck7";
regulator-min-microvolt = <500000>;
regulator-max-microvolt = <2000000>;
regulator-ramp-delay = <2500>;
};
ldo1: LDO1 {
regulator-name = "ldo1";
regulator-min-microvolt = <800000>;
regulator-max-microvolt = <3300000>;
};
ldo2: LDO2 {
regulator-name = "ldo2";
regulator-min-microvolt = <800000>;
regulator-max-microvolt = <3300000>;
};
ldo3: LDO3 {
regulator-name = "ldo3";
regulator-min-microvolt = <800000>;
regulator-max-microvolt = <3300000>;
};
ldo4: LDO4 {
regulator-name = "ldo4";
regulator-min-microvolt = <800000>;
regulator-max-microvolt = <3300000>;
};
ldo5: LDO5 {
regulator-name = "ldo5";
regulator-min-microvolt = <800000>;
regulator-max-microvolt = <3300000>;
};
ldo6: LDO6 {
regulator-name = "ldo6";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
};
ldo7_reg: LDO7 {
regulator-name = "ldo7";
regulator-min-microvolt = <800000>;
regulator-max-microvolt = <3300000>;
};
};
leds {
compatible = "rohm,bd71828-leds";
led-1 {
rohm,led-compatible = "bd71828-grnled";
function = LED_FUNCTION_INDICATOR;
color = <LED_COLOR_ID_GREEN>;
};
led-2 {
rohm,led-compatible = "bd71828-ambled";
function = LED_FUNCTION_CHARGING;
color = <LED_COLOR_ID_AMBER>;
};
};
};
};
...@@ -305,10 +305,10 @@ config COMMON_CLK_MMP2 ...@@ -305,10 +305,10 @@ config COMMON_CLK_MMP2
Support for Marvell MMP2 and MMP3 SoC clocks Support for Marvell MMP2 and MMP3 SoC clocks
config COMMON_CLK_BD718XX config COMMON_CLK_BD718XX
tristate "Clock driver for ROHM BD718x7 PMIC" tristate "Clock driver for 32K clk gates on ROHM PMICs"
depends on MFD_ROHM_BD718XX || MFD_ROHM_BD70528 depends on MFD_ROHM_BD718XX || MFD_ROHM_BD70528 || MFD_ROHM_BD71828
help help
This driver supports ROHM BD71837, ROHM BD71847 and This driver supports ROHM BD71837, ROHM BD71847, ROHM BD71828 and
ROHM BD70528 PMICs clock gates. ROHM BD70528 PMICs clock gates.
config COMMON_CLK_FIXED_MMIO config COMMON_CLK_FIXED_MMIO
......
...@@ -7,12 +7,25 @@ ...@@ -7,12 +7,25 @@
#include <linux/err.h> #include <linux/err.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/mfd/rohm-bd718x7.h> #include <linux/mfd/rohm-generic.h>
#include <linux/mfd/rohm-bd70528.h>
#include <linux/clk-provider.h> #include <linux/clk-provider.h>
#include <linux/clkdev.h> #include <linux/clkdev.h>
#include <linux/regmap.h> #include <linux/regmap.h>
/* clk control registers */
/* BD70528 */
#define BD70528_REG_OUT32K 0x2c
/* BD71828 */
#define BD71828_REG_OUT32K 0x4B
/* BD71837 and BD71847 */
#define BD718XX_REG_OUT32K 0x2E
/*
* BD71837, BD71847, BD70528 and BD71828 all use bit [0] to clk output control
*/
#define CLK_OUT_EN_MASK BIT(0)
struct bd718xx_clk { struct bd718xx_clk {
struct clk_hw hw; struct clk_hw hw;
u8 reg; u8 reg;
...@@ -21,10 +34,8 @@ struct bd718xx_clk { ...@@ -21,10 +34,8 @@ struct bd718xx_clk {
struct rohm_regmap_dev *mfd; struct rohm_regmap_dev *mfd;
}; };
static int bd71837_clk_set(struct clk_hw *hw, int status) static int bd71837_clk_set(struct bd718xx_clk *c, unsigned int status)
{ {
struct bd718xx_clk *c = container_of(hw, struct bd718xx_clk, hw);
return regmap_update_bits(c->mfd->regmap, c->reg, c->mask, status); return regmap_update_bits(c->mfd->regmap, c->reg, c->mask, status);
} }
...@@ -33,14 +44,16 @@ static void bd71837_clk_disable(struct clk_hw *hw) ...@@ -33,14 +44,16 @@ static void bd71837_clk_disable(struct clk_hw *hw)
int rv; int rv;
struct bd718xx_clk *c = container_of(hw, struct bd718xx_clk, hw); struct bd718xx_clk *c = container_of(hw, struct bd718xx_clk, hw);
rv = bd71837_clk_set(hw, 0); rv = bd71837_clk_set(c, 0);
if (rv) if (rv)
dev_dbg(&c->pdev->dev, "Failed to disable 32K clk (%d)\n", rv); dev_dbg(&c->pdev->dev, "Failed to disable 32K clk (%d)\n", rv);
} }
static int bd71837_clk_enable(struct clk_hw *hw) static int bd71837_clk_enable(struct clk_hw *hw)
{ {
return bd71837_clk_set(hw, 1); struct bd718xx_clk *c = container_of(hw, struct bd718xx_clk, hw);
return bd71837_clk_set(c, 0xffffffff);
} }
static int bd71837_clk_is_enabled(struct clk_hw *hw) static int bd71837_clk_is_enabled(struct clk_hw *hw)
...@@ -74,6 +87,7 @@ static int bd71837_clk_probe(struct platform_device *pdev) ...@@ -74,6 +87,7 @@ static int bd71837_clk_probe(struct platform_device *pdev)
.name = "bd718xx-32k-out", .name = "bd718xx-32k-out",
.ops = &bd71837_clk_ops, .ops = &bd71837_clk_ops,
}; };
enum rohm_chip_type chip = platform_get_device_id(pdev)->driver_data;
c = devm_kzalloc(&pdev->dev, sizeof(*c), GFP_KERNEL); c = devm_kzalloc(&pdev->dev, sizeof(*c), GFP_KERNEL);
if (!c) if (!c)
...@@ -87,15 +101,19 @@ static int bd71837_clk_probe(struct platform_device *pdev) ...@@ -87,15 +101,19 @@ static int bd71837_clk_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "No parent clk found\n"); dev_err(&pdev->dev, "No parent clk found\n");
return -EINVAL; return -EINVAL;
} }
switch (mfd->chip_type) { switch (chip) {
case ROHM_CHIP_TYPE_BD71837: case ROHM_CHIP_TYPE_BD71837:
case ROHM_CHIP_TYPE_BD71847: case ROHM_CHIP_TYPE_BD71847:
c->reg = BD718XX_REG_OUT32K; c->reg = BD718XX_REG_OUT32K;
c->mask = BD718XX_OUT32K_EN; c->mask = CLK_OUT_EN_MASK;
break;
case ROHM_CHIP_TYPE_BD71828:
c->reg = BD71828_REG_OUT32K;
c->mask = CLK_OUT_EN_MASK;
break; break;
case ROHM_CHIP_TYPE_BD70528: case ROHM_CHIP_TYPE_BD70528:
c->reg = BD70528_REG_CLK_OUT; c->reg = BD70528_REG_OUT32K;
c->mask = BD70528_CLK_OUT_EN_MASK; c->mask = CLK_OUT_EN_MASK;
break; break;
default: default:
dev_err(&pdev->dev, "Unknown clk chip\n"); dev_err(&pdev->dev, "Unknown clk chip\n");
...@@ -121,11 +139,21 @@ static int bd71837_clk_probe(struct platform_device *pdev) ...@@ -121,11 +139,21 @@ static int bd71837_clk_probe(struct platform_device *pdev)
return rval; return rval;
} }
static const struct platform_device_id bd718x7_clk_id[] = {
{ "bd71837-clk", ROHM_CHIP_TYPE_BD71837 },
{ "bd71847-clk", ROHM_CHIP_TYPE_BD71847 },
{ "bd70528-clk", ROHM_CHIP_TYPE_BD70528 },
{ "bd71828-clk", ROHM_CHIP_TYPE_BD71828 },
{ },
};
MODULE_DEVICE_TABLE(platform, bd718x7_clk_id);
static struct platform_driver bd71837_clk = { static struct platform_driver bd71837_clk = {
.driver = { .driver = {
.name = "bd718xx-clk", .name = "bd718xx-clk",
}, },
.probe = bd71837_clk_probe, .probe = bd71837_clk_probe,
.id_table = bd718x7_clk_id,
}; };
module_platform_driver(bd71837_clk); module_platform_driver(bd71837_clk);
......
...@@ -1035,6 +1035,18 @@ config GPIO_BD70528 ...@@ -1035,6 +1035,18 @@ config GPIO_BD70528
This driver can also be built as a module. If so, the module This driver can also be built as a module. If so, the module
will be called gpio-bd70528. will be called gpio-bd70528.
config GPIO_BD71828
tristate "ROHM BD71828 GPIO support"
depends on MFD_ROHM_BD71828
help
Support for GPIOs on ROHM BD71828 PMIC. There are three GPIOs
available on the ROHM PMIC in total. The GPIOs are limited to
outputs only and pins must be configured to GPIO outputs by
OTP. Enable this only if you want to use these pins as outputs.
This driver can also be built as a module. If so, the module
will be called gpio-bd71828.
config GPIO_BD9571MWV config GPIO_BD9571MWV
tristate "ROHM BD9571 GPIO support" tristate "ROHM BD9571 GPIO support"
depends on MFD_BD9571MWV depends on MFD_BD9571MWV
......
...@@ -37,6 +37,7 @@ obj-$(CONFIG_GPIO_ATH79) += gpio-ath79.o ...@@ -37,6 +37,7 @@ obj-$(CONFIG_GPIO_ATH79) += gpio-ath79.o
obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o
obj-$(CONFIG_GPIO_BCM_XGS_IPROC) += gpio-xgs-iproc.o obj-$(CONFIG_GPIO_BCM_XGS_IPROC) += gpio-xgs-iproc.o
obj-$(CONFIG_GPIO_BD70528) += gpio-bd70528.o obj-$(CONFIG_GPIO_BD70528) += gpio-bd70528.o
obj-$(CONFIG_GPIO_BD71828) += gpio-bd71828.o
obj-$(CONFIG_GPIO_BD9571MWV) += gpio-bd9571mwv.o obj-$(CONFIG_GPIO_BD9571MWV) += gpio-bd9571mwv.o
obj-$(CONFIG_GPIO_BRCMSTB) += gpio-brcmstb.o obj-$(CONFIG_GPIO_BRCMSTB) += gpio-brcmstb.o
obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o
......
// SPDX-License-Identifier: GPL-2.0-only
// Copyright (C) 2018 ROHM Semiconductors
#include <linux/gpio/driver.h>
#include <linux/mfd/rohm-bd71828.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#define GPIO_OUT_REG(off) (BD71828_REG_GPIO_CTRL1 + (off))
#define HALL_GPIO_OFFSET 3
/*
* These defines can be removed when
* "gpio: Add definition for GPIO direction"
* (9208b1e77d6e8e9776f34f46ef4079ecac9c3c25 in GPIO tree) gets merged,
*/
#ifndef GPIO_LINE_DIRECTION_IN
#define GPIO_LINE_DIRECTION_IN 1
#define GPIO_LINE_DIRECTION_OUT 0
#endif
struct bd71828_gpio {
struct rohm_regmap_dev chip;
struct gpio_chip gpio;
};
static void bd71828_gpio_set(struct gpio_chip *chip, unsigned int offset,
int value)
{
int ret;
struct bd71828_gpio *bdgpio = gpiochip_get_data(chip);
u8 val = (value) ? BD71828_GPIO_OUT_HI : BD71828_GPIO_OUT_LO;
/*
* The HALL input pin can only be used as input. If this is the pin
* we are dealing with - then we are done
*/
if (offset == HALL_GPIO_OFFSET)
return;
ret = regmap_update_bits(bdgpio->chip.regmap, GPIO_OUT_REG(offset),
BD71828_GPIO_OUT_MASK, val);
if (ret)
dev_err(bdgpio->chip.dev, "Could not set gpio to %d\n", value);
}
static int bd71828_gpio_get(struct gpio_chip *chip, unsigned int offset)
{
int ret;
unsigned int val;
struct bd71828_gpio *bdgpio = gpiochip_get_data(chip);
if (offset == HALL_GPIO_OFFSET)
ret = regmap_read(bdgpio->chip.regmap, BD71828_REG_IO_STAT,
&val);
else
ret = regmap_read(bdgpio->chip.regmap, GPIO_OUT_REG(offset),
&val);
if (!ret)
ret = (val & BD71828_GPIO_OUT_MASK);
return ret;
}
static int bd71828_gpio_set_config(struct gpio_chip *chip, unsigned int offset,
unsigned long config)
{
struct bd71828_gpio *bdgpio = gpiochip_get_data(chip);
if (offset == HALL_GPIO_OFFSET)
return -ENOTSUPP;
switch (pinconf_to_config_param(config)) {
case PIN_CONFIG_DRIVE_OPEN_DRAIN:
return regmap_update_bits(bdgpio->chip.regmap,
GPIO_OUT_REG(offset),
BD71828_GPIO_DRIVE_MASK,
BD71828_GPIO_OPEN_DRAIN);
case PIN_CONFIG_DRIVE_PUSH_PULL:
return regmap_update_bits(bdgpio->chip.regmap,
GPIO_OUT_REG(offset),
BD71828_GPIO_DRIVE_MASK,
BD71828_GPIO_PUSH_PULL);
default:
break;
}
return -ENOTSUPP;
}
static int bd71828_get_direction(struct gpio_chip *chip, unsigned int offset)
{
/*
* Pin usage is selected by OTP data. We can't read it runtime. Hence
* we trust that if the pin is not excluded by "gpio-reserved-ranges"
* the OTP configuration is set to OUT. (Other pins but HALL input pin
* on BD71828 can't really be used for general purpose input - input
* states are used for specific cases like regulator control or
* PMIC_ON_REQ.
*/
if (offset == HALL_GPIO_OFFSET)
return GPIO_LINE_DIRECTION_IN;
return GPIO_LINE_DIRECTION_OUT;
}
static int bd71828_probe(struct platform_device *pdev)
{
struct bd71828_gpio *bdgpio;
struct rohm_regmap_dev *bd71828;
bd71828 = dev_get_drvdata(pdev->dev.parent);
if (!bd71828) {
dev_err(&pdev->dev, "No MFD driver data\n");
return -EINVAL;
}
bdgpio = devm_kzalloc(&pdev->dev, sizeof(*bdgpio),
GFP_KERNEL);
if (!bdgpio)
return -ENOMEM;
bdgpio->chip.dev = &pdev->dev;
bdgpio->gpio.parent = pdev->dev.parent;
bdgpio->gpio.label = "bd71828-gpio";
bdgpio->gpio.owner = THIS_MODULE;
bdgpio->gpio.get_direction = bd71828_get_direction;
bdgpio->gpio.set_config = bd71828_gpio_set_config;
bdgpio->gpio.can_sleep = true;
bdgpio->gpio.get = bd71828_gpio_get;
bdgpio->gpio.set = bd71828_gpio_set;
bdgpio->gpio.base = -1;
/*
* See if we need some implementation to mark some PINs as
* not controllable based on DT info or if core can handle
* "gpio-reserved-ranges" and exclude them from control
*/
bdgpio->gpio.ngpio = 4;
bdgpio->gpio.of_node = pdev->dev.parent->of_node;
bdgpio->chip.regmap = bd71828->regmap;
return devm_gpiochip_add_data(&pdev->dev, &bdgpio->gpio,
bdgpio);
}
static struct platform_driver bd71828_gpio = {
.driver = {
.name = "bd71828-gpio"
},
.probe = bd71828_probe,
};
module_platform_driver(bd71828_gpio);
MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
MODULE_DESCRIPTION("BD71828 voltage regulator driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:bd71828-gpio");
...@@ -758,6 +758,7 @@ config MFD_MAX77650 ...@@ -758,6 +758,7 @@ config MFD_MAX77650
depends on OF || COMPILE_TEST depends on OF || COMPILE_TEST
select MFD_CORE select MFD_CORE
select REGMAP_I2C select REGMAP_I2C
select REGMAP_IRQ
help help
Say Y here to add support for Maxim Semiconductor MAX77650 and Say Y here to add support for Maxim Semiconductor MAX77650 and
MAX77651 Power Management ICs. This is the core multifunction MAX77651 Power Management ICs. This is the core multifunction
...@@ -1065,7 +1066,7 @@ config MFD_RN5T618 ...@@ -1065,7 +1066,7 @@ config MFD_RN5T618
functionality of the device. functionality of the device.
config MFD_SEC_CORE config MFD_SEC_CORE
tristate "SAMSUNG Electronics PMIC Series Support" tristate "Samsung Electronics PMIC Series Support"
depends on I2C=y depends on I2C=y
select MFD_CORE select MFD_CORE
select REGMAP_I2C select REGMAP_I2C
...@@ -1906,6 +1907,21 @@ config MFD_ROHM_BD70528 ...@@ -1906,6 +1907,21 @@ config MFD_ROHM_BD70528
10 bits SAR ADC for battery temperature monitor and 1S battery 10 bits SAR ADC for battery temperature monitor and 1S battery
charger. charger.
config MFD_ROHM_BD71828
tristate "ROHM BD71828 Power Management IC"
depends on I2C=y
depends on OF
select REGMAP_I2C
select REGMAP_IRQ
select MFD_CORE
help
Select this option to get support for the ROHM BD71828 Power
Management IC. BD71828GW is a single-chip power management IC for
battery-powered portable devices. The IC integrates 7 buck
converters, 7 LDOs, and a 1500 mA single-cell linear charger.
Also included is a Coulomb counter, a real-time clock (RTC), and
a 32.768 kHz clock gate.
config MFD_STM32_LPTIMER config MFD_STM32_LPTIMER
tristate "Support for STM32 Low-Power Timer" tristate "Support for STM32 Low-Power Timer"
depends on (ARCH_STM32 && OF) || COMPILE_TEST depends on (ARCH_STM32 && OF) || COMPILE_TEST
...@@ -1960,6 +1976,18 @@ config MFD_STMFX ...@@ -1960,6 +1976,18 @@ config MFD_STMFX
additional drivers must be enabled in order to use the functionality additional drivers must be enabled in order to use the functionality
of the device. of the device.
config MFD_WCD934X
tristate "Support for WCD9340/WCD9341 Codec"
depends on SLIMBUS
select REGMAP
select REGMAP_SLIMBUS
select REGMAP_IRQ
select MFD_CORE
help
Support for the Qualcomm WCD9340/WCD9341 Codec.
This driver provides common support WCD934x audio codec and its
associated Pin Controller, Soundwire Controller and Audio codec.
menu "Multimedia Capabilities Port drivers" menu "Multimedia Capabilities Port drivers"
depends on ARCH_SA1100 depends on ARCH_SA1100
......
...@@ -58,6 +58,7 @@ endif ...@@ -58,6 +58,7 @@ endif
ifeq ($(CONFIG_MFD_CS47L24),y) ifeq ($(CONFIG_MFD_CS47L24),y)
obj-$(CONFIG_MFD_ARIZONA) += cs47l24-tables.o obj-$(CONFIG_MFD_ARIZONA) += cs47l24-tables.o
endif endif
obj-$(CONFIG_MFD_WCD934X) += wcd934x.o
obj-$(CONFIG_MFD_WM8400) += wm8400-core.o obj-$(CONFIG_MFD_WM8400) += wm8400-core.o
wm831x-objs := wm831x-core.o wm831x-irq.o wm831x-otp.o wm831x-objs := wm831x-core.o wm831x-irq.o wm831x-otp.o
wm831x-objs += wm831x-auxadc.o wm831x-objs += wm831x-auxadc.o
...@@ -252,6 +253,7 @@ obj-$(CONFIG_MFD_MXS_LRADC) += mxs-lradc.o ...@@ -252,6 +253,7 @@ obj-$(CONFIG_MFD_MXS_LRADC) += mxs-lradc.o
obj-$(CONFIG_MFD_SC27XX_PMIC) += sprd-sc27xx-spi.o obj-$(CONFIG_MFD_SC27XX_PMIC) += sprd-sc27xx-spi.o
obj-$(CONFIG_RAVE_SP_CORE) += rave-sp.o obj-$(CONFIG_RAVE_SP_CORE) += rave-sp.o
obj-$(CONFIG_MFD_ROHM_BD70528) += rohm-bd70528.o obj-$(CONFIG_MFD_ROHM_BD70528) += rohm-bd70528.o
obj-$(CONFIG_MFD_ROHM_BD71828) += rohm-bd71828.o
obj-$(CONFIG_MFD_ROHM_BD718XX) += rohm-bd718x7.o obj-$(CONFIG_MFD_ROHM_BD718XX) += rohm-bd718x7.o
obj-$(CONFIG_MFD_STMFX) += stmfx.o obj-$(CONFIG_MFD_STMFX) += stmfx.o
......
...@@ -631,8 +631,8 @@ static const struct mfd_cell ab8500_devs[] = { ...@@ -631,8 +631,8 @@ static const struct mfd_cell ab8500_devs[] = {
NULL, NULL, 0, 0, "stericsson,ab8500-ext-regulator"), NULL, NULL, 0, 0, "stericsson,ab8500-ext-regulator"),
OF_MFD_CELL("ab8500-regulator", OF_MFD_CELL("ab8500-regulator",
NULL, NULL, 0, 0, "stericsson,ab8500-regulator"), NULL, NULL, 0, 0, "stericsson,ab8500-regulator"),
OF_MFD_CELL("abx500-clk", OF_MFD_CELL("ab8500-clk",
NULL, NULL, 0, 0, "stericsson,abx500-clk"), NULL, NULL, 0, 0, "stericsson,ab8500-clk"),
OF_MFD_CELL("ab8500-gpadc", OF_MFD_CELL("ab8500-gpadc",
NULL, NULL, 0, 0, "stericsson,ab8500-gpadc"), NULL, NULL, 0, 0, "stericsson,ab8500-gpadc"),
OF_MFD_CELL("ab8500-rtc", OF_MFD_CELL("ab8500-rtc",
...@@ -718,17 +718,20 @@ static const struct mfd_cell ab8505_devs[] = { ...@@ -718,17 +718,20 @@ static const struct mfd_cell ab8505_devs[] = {
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
{ {
.name = "ab8500-debug", .name = "ab8500-debug",
.of_compatible = "stericsson,ab8500-debug",
}, },
#endif #endif
{ {
.name = "ab8500-sysctrl", .name = "ab8500-sysctrl",
.of_compatible = "stericsson,ab8500-sysctrl",
}, },
{ {
.name = "ab8500-regulator", .name = "ab8500-regulator",
.of_compatible = "stericsson,ab8505-regulator",
}, },
{ {
.name = "abx500-clk", .name = "abx500-clk",
.of_compatible = "stericsson,abx500-clk", .of_compatible = "stericsson,ab8500-clk",
}, },
{ {
.name = "ab8500-gpadc", .name = "ab8500-gpadc",
...@@ -736,25 +739,32 @@ static const struct mfd_cell ab8505_devs[] = { ...@@ -736,25 +739,32 @@ static const struct mfd_cell ab8505_devs[] = {
}, },
{ {
.name = "ab8500-rtc", .name = "ab8500-rtc",
.of_compatible = "stericsson,ab8500-rtc",
}, },
{ {
.name = "ab8500-acc-det", .name = "ab8500-acc-det",
.of_compatible = "stericsson,ab8500-acc-det",
}, },
{ {
.name = "ab8500-poweron-key", .name = "ab8500-poweron-key",
.of_compatible = "stericsson,ab8500-poweron-key",
}, },
{ {
.name = "ab8500-pwm", .name = "ab8500-pwm",
.of_compatible = "stericsson,ab8500-pwm",
.id = 1, .id = 1,
}, },
{ {
.name = "pinctrl-ab8505", .name = "pinctrl-ab8505",
.of_compatible = "stericsson,ab8505-gpio",
}, },
{ {
.name = "ab8500-usb", .name = "ab8500-usb",
.of_compatible = "stericsson,ab8500-usb",
}, },
{ {
.name = "ab8500-codec", .name = "ab8500-codec",
.of_compatible = "stericsson,ab8500-codec",
}, },
{ {
.name = "ab-iddet", .name = "ab-iddet",
...@@ -1276,7 +1286,7 @@ static int ab8500_probe(struct platform_device *pdev) ...@@ -1276,7 +1286,7 @@ static int ab8500_probe(struct platform_device *pdev)
static const struct platform_device_id ab8500_id[] = { static const struct platform_device_id ab8500_id[] = {
{ "ab8500-core", AB8500_VERSION_AB8500 }, { "ab8500-core", AB8500_VERSION_AB8500 },
{ "ab8505-i2c", AB8500_VERSION_AB8505 }, { "ab8505-core", AB8500_VERSION_AB8505 },
{ "ab9540-i2c", AB8500_VERSION_AB9540 }, { "ab9540-i2c", AB8500_VERSION_AB9540 },
{ "ab8540-i2c", AB8500_VERSION_AB8540 }, { "ab8540-i2c", AB8500_VERSION_AB8540 },
{ } { }
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
struct atmel_hlcdc_regmap { struct atmel_hlcdc_regmap {
void __iomem *regs; void __iomem *regs;
struct device *dev;
}; };
static const struct mfd_cell atmel_hlcdc_cells[] = { static const struct mfd_cell atmel_hlcdc_cells[] = {
...@@ -39,10 +40,17 @@ static int regmap_atmel_hlcdc_reg_write(void *context, unsigned int reg, ...@@ -39,10 +40,17 @@ static int regmap_atmel_hlcdc_reg_write(void *context, unsigned int reg,
if (reg <= ATMEL_HLCDC_DIS) { if (reg <= ATMEL_HLCDC_DIS) {
u32 status; u32 status;
int ret;
readl_poll_timeout_atomic(hregmap->regs + ATMEL_HLCDC_SR,
status, !(status & ATMEL_HLCDC_SIP), ret = readl_poll_timeout_atomic(hregmap->regs + ATMEL_HLCDC_SR,
1, 100); status,
!(status & ATMEL_HLCDC_SIP),
1, 100);
if (ret) {
dev_err(hregmap->dev,
"Timeout! Clock domain synchronization is in progress!\n");
return ret;
}
} }
writel(val, hregmap->regs + reg); writel(val, hregmap->regs + reg);
...@@ -90,6 +98,8 @@ static int atmel_hlcdc_probe(struct platform_device *pdev) ...@@ -90,6 +98,8 @@ static int atmel_hlcdc_probe(struct platform_device *pdev)
if (IS_ERR(hregmap->regs)) if (IS_ERR(hregmap->regs))
return PTR_ERR(hregmap->regs); return PTR_ERR(hregmap->regs);
hregmap->dev = &pdev->dev;
hlcdc->irq = platform_get_irq(pdev, 0); hlcdc->irq = platform_get_irq(pdev, 0);
if (hlcdc->irq < 0) if (hlcdc->irq < 0)
return hlcdc->irq; return hlcdc->irq;
......
...@@ -126,7 +126,7 @@ static const struct regmap_range axp288_writeable_ranges[] = { ...@@ -126,7 +126,7 @@ static const struct regmap_range axp288_writeable_ranges[] = {
static const struct regmap_range axp288_volatile_ranges[] = { static const struct regmap_range axp288_volatile_ranges[] = {
regmap_reg_range(AXP20X_PWR_INPUT_STATUS, AXP288_POWER_REASON), regmap_reg_range(AXP20X_PWR_INPUT_STATUS, AXP288_POWER_REASON),
regmap_reg_range(AXP288_BC_GLOBAL, AXP288_BC_GLOBAL), regmap_reg_range(AXP288_BC_GLOBAL, AXP288_BC_GLOBAL),
regmap_reg_range(AXP288_BC_DET_STAT, AXP288_BC_DET_STAT), regmap_reg_range(AXP288_BC_DET_STAT, AXP20X_VBUS_IPSOUT_MGMT),
regmap_reg_range(AXP20X_CHRG_BAK_CTRL, AXP20X_CHRG_BAK_CTRL), regmap_reg_range(AXP20X_CHRG_BAK_CTRL, AXP20X_CHRG_BAK_CTRL),
regmap_reg_range(AXP20X_IRQ1_EN, AXP20X_IPSOUT_V_HIGH_L), regmap_reg_range(AXP20X_IRQ1_EN, AXP20X_IPSOUT_V_HIGH_L),
regmap_reg_range(AXP20X_TIMER_CTRL, AXP20X_TIMER_CTRL), regmap_reg_range(AXP20X_TIMER_CTRL, AXP20X_TIMER_CTRL),
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
* Copyright (C) 2014 Google, Inc. * Copyright (C) 2014 Google, Inc.
*/ */
#include <linux/kconfig.h>
#include <linux/mfd/core.h> #include <linux/mfd/core.h>
#include <linux/mfd/cros_ec.h> #include <linux/mfd/cros_ec.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -87,6 +88,10 @@ static const struct mfd_cell cros_usbpd_charger_cells[] = { ...@@ -87,6 +88,10 @@ static const struct mfd_cell cros_usbpd_charger_cells[] = {
{ .name = "cros-usbpd-logger", }, { .name = "cros-usbpd-logger", },
}; };
static const struct mfd_cell cros_usbpd_notify_cells[] = {
{ .name = "cros-usbpd-notify", },
};
static const struct cros_feature_to_cells cros_subdevices[] = { static const struct cros_feature_to_cells cros_subdevices[] = {
{ {
.id = EC_FEATURE_CEC, .id = EC_FEATURE_CEC,
...@@ -202,6 +207,23 @@ static int ec_device_probe(struct platform_device *pdev) ...@@ -202,6 +207,23 @@ static int ec_device_probe(struct platform_device *pdev)
} }
} }
/*
* The PD notifier driver cell is separate since it only needs to be
* explicitly added on platforms that don't have the PD notifier ACPI
* device entry defined.
*/
if (IS_ENABLED(CONFIG_OF)) {
if (cros_ec_check_features(ec, EC_FEATURE_USB_PD)) {
retval = mfd_add_hotplug_devices(ec->dev,
cros_usbpd_notify_cells,
ARRAY_SIZE(cros_usbpd_notify_cells));
if (retval)
dev_err(ec->dev,
"failed to add PD notify devices: %d\n",
retval);
}
}
/* /*
* The following subdevices cannot be detected by sending the * The following subdevices cannot be detected by sending the
* EC_FEATURE_GET_CMD to the Embedded Controller device. * EC_FEATURE_GET_CMD to the Embedded Controller device.
......
...@@ -112,6 +112,7 @@ static const struct reg_default cs47l15_reg_default[] = { ...@@ -112,6 +112,7 @@ static const struct reg_default cs47l15_reg_default[] = {
{ 0x000001dd, 0x0011 }, /* R477 (0x1DD) - FLL AO Control 11 */ { 0x000001dd, 0x0011 }, /* R477 (0x1DD) - FLL AO Control 11 */
{ 0x00000218, 0x00e6 }, /* R536 (0x218) - Mic Bias Ctrl 1 */ { 0x00000218, 0x00e6 }, /* R536 (0x218) - Mic Bias Ctrl 1 */
{ 0x0000021c, 0x0222 }, /* R540 (0x21C) - Mic Bias Ctrl 5 */ { 0x0000021c, 0x0222 }, /* R540 (0x21C) - Mic Bias Ctrl 5 */
{ 0x00000293, 0x0080 }, /* R659 (0x293) - Accessory Detect Mode 1 */
{ 0x00000299, 0x0000 }, /* R665 (0x299) - Headphone Detect 0 */ { 0x00000299, 0x0000 }, /* R665 (0x299) - Headphone Detect 0 */
{ 0x0000029b, 0x0000 }, /* R667 (0x29B) - Headphone Detect 1 */ { 0x0000029b, 0x0000 }, /* R667 (0x29B) - Headphone Detect 1 */
{ 0x000002a2, 0x0010 }, /* R674 (0x2A2) - Mic Detect 1 Control 0 */ { 0x000002a2, 0x0010 }, /* R674 (0x2A2) - Mic Detect 1 Control 0 */
......
...@@ -233,6 +233,14 @@ static struct resource da9062_onkey_resources[] = { ...@@ -233,6 +233,14 @@ static struct resource da9062_onkey_resources[] = {
DEFINE_RES_NAMED(DA9062_IRQ_ONKEY, 1, "ONKEY", IORESOURCE_IRQ), DEFINE_RES_NAMED(DA9062_IRQ_ONKEY, 1, "ONKEY", IORESOURCE_IRQ),
}; };
static struct resource da9062_gpio_resources[] = {
DEFINE_RES_NAMED(DA9062_IRQ_GPI0, 1, "GPI0", IORESOURCE_IRQ),
DEFINE_RES_NAMED(DA9062_IRQ_GPI1, 1, "GPI1", IORESOURCE_IRQ),
DEFINE_RES_NAMED(DA9062_IRQ_GPI2, 1, "GPI2", IORESOURCE_IRQ),
DEFINE_RES_NAMED(DA9062_IRQ_GPI3, 1, "GPI3", IORESOURCE_IRQ),
DEFINE_RES_NAMED(DA9062_IRQ_GPI4, 1, "GPI4", IORESOURCE_IRQ),
};
static const struct mfd_cell da9062_devs[] = { static const struct mfd_cell da9062_devs[] = {
{ {
.name = "da9062-core", .name = "da9062-core",
...@@ -248,7 +256,7 @@ static const struct mfd_cell da9062_devs[] = { ...@@ -248,7 +256,7 @@ static const struct mfd_cell da9062_devs[] = {
.name = "da9062-watchdog", .name = "da9062-watchdog",
.num_resources = ARRAY_SIZE(da9062_wdt_resources), .num_resources = ARRAY_SIZE(da9062_wdt_resources),
.resources = da9062_wdt_resources, .resources = da9062_wdt_resources,
.of_compatible = "dlg,da9062-wdt", .of_compatible = "dlg,da9062-watchdog",
}, },
{ {
.name = "da9062-thermal", .name = "da9062-thermal",
...@@ -266,7 +274,13 @@ static const struct mfd_cell da9062_devs[] = { ...@@ -266,7 +274,13 @@ static const struct mfd_cell da9062_devs[] = {
.name = "da9062-onkey", .name = "da9062-onkey",
.num_resources = ARRAY_SIZE(da9062_onkey_resources), .num_resources = ARRAY_SIZE(da9062_onkey_resources),
.resources = da9062_onkey_resources, .resources = da9062_onkey_resources,
.of_compatible = "dlg,da9062-onkey", .of_compatible = "dlg,da9062-onkey",
},
{
.name = "da9062-gpio",
.num_resources = ARRAY_SIZE(da9062_gpio_resources),
.resources = da9062_gpio_resources,
.of_compatible = "dlg,da9062-gpio",
}, },
}; };
......
...@@ -542,102 +542,6 @@ static struct dsiescclk dsiescclk[3] = { ...@@ -542,102 +542,6 @@ static struct dsiescclk dsiescclk[3] = {
} }
}; };
/*
* Used by MCDE to setup all necessary PRCMU registers
*/
#define PRCMU_RESET_DSIPLL 0x00004000
#define PRCMU_UNCLAMP_DSIPLL 0x00400800
#define PRCMU_CLK_PLL_DIV_SHIFT 0
#define PRCMU_CLK_PLL_SW_SHIFT 5
#define PRCMU_CLK_38 (1 << 9)
#define PRCMU_CLK_38_SRC (1 << 10)
#define PRCMU_CLK_38_DIV (1 << 11)
/* PLLDIV=12, PLLSW=4 (PLLDDR) */
#define PRCMU_DSI_CLOCK_SETTING 0x0000008C
/* DPI 50000000 Hz */
#define PRCMU_DPI_CLOCK_SETTING ((1 << PRCMU_CLK_PLL_SW_SHIFT) | \
(16 << PRCMU_CLK_PLL_DIV_SHIFT))
#define PRCMU_DSI_LP_CLOCK_SETTING 0x00000E00
/* D=101, N=1, R=4, SELDIV2=0 */
#define PRCMU_PLLDSI_FREQ_SETTING 0x00040165
#define PRCMU_ENABLE_PLLDSI 0x00000001
#define PRCMU_DISABLE_PLLDSI 0x00000000
#define PRCMU_RELEASE_RESET_DSS 0x0000400C
#define PRCMU_DSI_PLLOUT_SEL_SETTING 0x00000202
/* ESC clk, div0=1, div1=1, div2=3 */
#define PRCMU_ENABLE_ESCAPE_CLOCK_DIV 0x07030101
#define PRCMU_DISABLE_ESCAPE_CLOCK_DIV 0x00030101
#define PRCMU_DSI_RESET_SW 0x00000007
#define PRCMU_PLLDSI_LOCKP_LOCKED 0x3
int db8500_prcmu_enable_dsipll(void)
{
int i;
/* Clear DSIPLL_RESETN */
writel(PRCMU_RESET_DSIPLL, PRCM_APE_RESETN_CLR);
/* Unclamp DSIPLL in/out */
writel(PRCMU_UNCLAMP_DSIPLL, PRCM_MMIP_LS_CLAMP_CLR);
/* Set DSI PLL FREQ */
writel(PRCMU_PLLDSI_FREQ_SETTING, PRCM_PLLDSI_FREQ);
writel(PRCMU_DSI_PLLOUT_SEL_SETTING, PRCM_DSI_PLLOUT_SEL);
/* Enable Escape clocks */
writel(PRCMU_ENABLE_ESCAPE_CLOCK_DIV, PRCM_DSITVCLK_DIV);
/* Start DSI PLL */
writel(PRCMU_ENABLE_PLLDSI, PRCM_PLLDSI_ENABLE);
/* Reset DSI PLL */
writel(PRCMU_DSI_RESET_SW, PRCM_DSI_SW_RESET);
for (i = 0; i < 10; i++) {
if ((readl(PRCM_PLLDSI_LOCKP) & PRCMU_PLLDSI_LOCKP_LOCKED)
== PRCMU_PLLDSI_LOCKP_LOCKED)
break;
udelay(100);
}
/* Set DSIPLL_RESETN */
writel(PRCMU_RESET_DSIPLL, PRCM_APE_RESETN_SET);
return 0;
}
int db8500_prcmu_disable_dsipll(void)
{
/* Disable dsi pll */
writel(PRCMU_DISABLE_PLLDSI, PRCM_PLLDSI_ENABLE);
/* Disable escapeclock */
writel(PRCMU_DISABLE_ESCAPE_CLOCK_DIV, PRCM_DSITVCLK_DIV);
return 0;
}
int db8500_prcmu_set_display_clocks(void)
{
unsigned long flags;
spin_lock_irqsave(&clk_mgt_lock, flags);
/* Grab the HW semaphore. */
while ((readl(PRCM_SEM) & PRCM_SEM_PRCM_SEM) != 0)
cpu_relax();
writel(PRCMU_DSI_CLOCK_SETTING, prcmu_base + PRCM_HDMICLK_MGT);
writel(PRCMU_DSI_LP_CLOCK_SETTING, prcmu_base + PRCM_TVCLK_MGT);
writel(PRCMU_DPI_CLOCK_SETTING, prcmu_base + PRCM_LCDCLK_MGT);
/* Release the HW semaphore. */
writel(0, PRCM_SEM);
spin_unlock_irqrestore(&clk_mgt_lock, flags);
return 0;
}
u32 db8500_prcmu_read(unsigned int reg) u32 db8500_prcmu_read(unsigned int reg)
{ {
return readl(prcmu_base + reg); return readl(prcmu_base + reg);
...@@ -3060,30 +2964,44 @@ static const struct mfd_cell db8500_prcmu_devs[] = { ...@@ -3060,30 +2964,44 @@ static const struct mfd_cell db8500_prcmu_devs[] = {
static int db8500_prcmu_register_ab8500(struct device *parent) static int db8500_prcmu_register_ab8500(struct device *parent)
{ {
struct device_node *np; struct device_node *np;
struct resource ab8500_resource; struct resource ab850x_resource;
const struct mfd_cell ab8500_cell = { const struct mfd_cell ab8500_cell = {
.name = "ab8500-core", .name = "ab8500-core",
.of_compatible = "stericsson,ab8500", .of_compatible = "stericsson,ab8500",
.id = AB8500_VERSION_AB8500, .id = AB8500_VERSION_AB8500,
.resources = &ab8500_resource, .resources = &ab850x_resource,
.num_resources = 1, .num_resources = 1,
}; };
const struct mfd_cell ab8505_cell = {
.name = "ab8505-core",
.of_compatible = "stericsson,ab8505",
.id = AB8500_VERSION_AB8505,
.resources = &ab850x_resource,
.num_resources = 1,
};
const struct mfd_cell *ab850x_cell;
if (!parent->of_node) if (!parent->of_node)
return -ENODEV; return -ENODEV;
/* Look up the device node, sneak the IRQ out of it */ /* Look up the device node, sneak the IRQ out of it */
for_each_child_of_node(parent->of_node, np) { for_each_child_of_node(parent->of_node, np) {
if (of_device_is_compatible(np, ab8500_cell.of_compatible)) if (of_device_is_compatible(np, ab8500_cell.of_compatible)) {
ab850x_cell = &ab8500_cell;
break; break;
}
if (of_device_is_compatible(np, ab8505_cell.of_compatible)) {
ab850x_cell = &ab8505_cell;
break;
}
} }
if (!np) { if (!np) {
dev_info(parent, "could not find AB8500 node in the device tree\n"); dev_info(parent, "could not find AB850X node in the device tree\n");
return -ENODEV; return -ENODEV;
} }
of_irq_to_resource_table(np, &ab8500_resource, 1); of_irq_to_resource_table(np, &ab850x_resource, 1);
return mfd_add_devices(parent, 0, &ab8500_cell, 1, NULL, 0, NULL); return mfd_add_devices(parent, 0, ab850x_cell, 1, NULL, 0, NULL);
} }
/** /**
......
...@@ -722,6 +722,8 @@ static int dln2_probe(struct usb_interface *interface, ...@@ -722,6 +722,8 @@ static int dln2_probe(struct usb_interface *interface,
const struct usb_device_id *usb_id) const struct usb_device_id *usb_id)
{ {
struct usb_host_interface *hostif = interface->cur_altsetting; struct usb_host_interface *hostif = interface->cur_altsetting;
struct usb_endpoint_descriptor *epin;
struct usb_endpoint_descriptor *epout;
struct device *dev = &interface->dev; struct device *dev = &interface->dev;
struct dln2_dev *dln2; struct dln2_dev *dln2;
int ret; int ret;
...@@ -731,12 +733,19 @@ static int dln2_probe(struct usb_interface *interface, ...@@ -731,12 +733,19 @@ static int dln2_probe(struct usb_interface *interface,
hostif->desc.bNumEndpoints < 2) hostif->desc.bNumEndpoints < 2)
return -ENODEV; return -ENODEV;
epin = &hostif->endpoint[0].desc;
epout = &hostif->endpoint[1].desc;
if (!usb_endpoint_is_bulk_out(epout))
return -ENODEV;
if (!usb_endpoint_is_bulk_in(epin))
return -ENODEV;
dln2 = kzalloc(sizeof(*dln2), GFP_KERNEL); dln2 = kzalloc(sizeof(*dln2), GFP_KERNEL);
if (!dln2) if (!dln2)
return -ENOMEM; return -ENOMEM;
dln2->ep_out = hostif->endpoint[0].desc.bEndpointAddress; dln2->ep_out = epout->bEndpointAddress;
dln2->ep_in = hostif->endpoint[1].desc.bEndpointAddress; dln2->ep_in = epin->bEndpointAddress;
dln2->usb_dev = usb_get_dev(interface_to_usbdev(interface)); dln2->usb_dev = usb_get_dev(interface_to_usbdev(interface));
dln2->interface = interface; dln2->interface = interface;
usb_set_intfdata(interface, dln2); usb_set_intfdata(interface, dln2);
......
...@@ -240,6 +240,19 @@ static const struct pci_device_id intel_lpss_pci_ids[] = { ...@@ -240,6 +240,19 @@ static const struct pci_device_id intel_lpss_pci_ids[] = {
{ PCI_VDEVICE(INTEL, 0x4b79), (kernel_ulong_t)&bxt_i2c_info }, { PCI_VDEVICE(INTEL, 0x4b79), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x4b7a), (kernel_ulong_t)&bxt_i2c_info }, { PCI_VDEVICE(INTEL, 0x4b7a), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x4b7b), (kernel_ulong_t)&bxt_i2c_info }, { PCI_VDEVICE(INTEL, 0x4b7b), (kernel_ulong_t)&bxt_i2c_info },
/* JSL */
{ PCI_VDEVICE(INTEL, 0x4da8), (kernel_ulong_t)&spt_uart_info },
{ PCI_VDEVICE(INTEL, 0x4da9), (kernel_ulong_t)&spt_uart_info },
{ PCI_VDEVICE(INTEL, 0x4daa), (kernel_ulong_t)&spt_info },
{ PCI_VDEVICE(INTEL, 0x4dab), (kernel_ulong_t)&spt_info },
{ PCI_VDEVICE(INTEL, 0x4daf), (kernel_ulong_t)&spt_uart_info },
{ PCI_VDEVICE(INTEL, 0x4dc5), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x4dc6), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x4de8), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x4de9), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x4dea), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x4deb), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x4dfb), (kernel_ulong_t)&spt_info },
/* APL */ /* APL */
{ PCI_VDEVICE(INTEL, 0x5aac), (kernel_ulong_t)&apl_i2c_info }, { PCI_VDEVICE(INTEL, 0x5aac), (kernel_ulong_t)&apl_i2c_info },
{ PCI_VDEVICE(INTEL, 0x5aae), (kernel_ulong_t)&apl_i2c_info }, { PCI_VDEVICE(INTEL, 0x5aae), (kernel_ulong_t)&apl_i2c_info },
......
...@@ -35,6 +35,9 @@ ...@@ -35,6 +35,9 @@
#define MADERA_32KZ_MCLK2 1 #define MADERA_32KZ_MCLK2 1
#define MADERA_RESET_MIN_US 2000
#define MADERA_RESET_MAX_US 3000
static const char * const madera_core_supplies[] = { static const char * const madera_core_supplies[] = {
"AVDD", "AVDD",
"DBVDD1", "DBVDD1",
...@@ -199,7 +202,7 @@ EXPORT_SYMBOL_GPL(madera_name_from_type); ...@@ -199,7 +202,7 @@ EXPORT_SYMBOL_GPL(madera_name_from_type);
#define MADERA_BOOT_POLL_INTERVAL_USEC 5000 #define MADERA_BOOT_POLL_INTERVAL_USEC 5000
#define MADERA_BOOT_POLL_TIMEOUT_USEC 25000 #define MADERA_BOOT_POLL_TIMEOUT_USEC 25000
static int madera_wait_for_boot(struct madera *madera) static int madera_wait_for_boot_noack(struct madera *madera)
{ {
ktime_t timeout; ktime_t timeout;
unsigned int val = 0; unsigned int val = 0;
...@@ -226,6 +229,13 @@ static int madera_wait_for_boot(struct madera *madera) ...@@ -226,6 +229,13 @@ static int madera_wait_for_boot(struct madera *madera)
ret = -ETIMEDOUT; ret = -ETIMEDOUT;
} }
return ret;
}
static int madera_wait_for_boot(struct madera *madera)
{
int ret = madera_wait_for_boot_noack(madera);
/* /*
* BOOT_DONE defaults to unmasked on boot so we must ack it. * BOOT_DONE defaults to unmasked on boot so we must ack it.
* Do this even after a timeout to avoid interrupt storms. * Do this even after a timeout to avoid interrupt storms.
...@@ -249,16 +259,13 @@ static int madera_soft_reset(struct madera *madera) ...@@ -249,16 +259,13 @@ static int madera_soft_reset(struct madera *madera)
} }
/* Allow time for internal clocks to startup after reset */ /* Allow time for internal clocks to startup after reset */
usleep_range(1000, 2000); usleep_range(MADERA_RESET_MIN_US, MADERA_RESET_MAX_US);
return 0; return 0;
} }
static void madera_enable_hard_reset(struct madera *madera) static void madera_enable_hard_reset(struct madera *madera)
{ {
if (!madera->pdata.reset)
return;
/* /*
* There are many existing out-of-tree users of these codecs that we * There are many existing out-of-tree users of these codecs that we
* can't break so preserve the expected behaviour of setting the line * can't break so preserve the expected behaviour of setting the line
...@@ -269,11 +276,9 @@ static void madera_enable_hard_reset(struct madera *madera) ...@@ -269,11 +276,9 @@ static void madera_enable_hard_reset(struct madera *madera)
static void madera_disable_hard_reset(struct madera *madera) static void madera_disable_hard_reset(struct madera *madera)
{ {
if (!madera->pdata.reset)
return;
gpiod_set_raw_value_cansleep(madera->pdata.reset, 1); gpiod_set_raw_value_cansleep(madera->pdata.reset, 1);
usleep_range(1000, 2000);
usleep_range(MADERA_RESET_MIN_US, MADERA_RESET_MAX_US);
} }
static int __maybe_unused madera_runtime_resume(struct device *dev) static int __maybe_unused madera_runtime_resume(struct device *dev)
...@@ -292,6 +297,8 @@ static int __maybe_unused madera_runtime_resume(struct device *dev) ...@@ -292,6 +297,8 @@ static int __maybe_unused madera_runtime_resume(struct device *dev)
regcache_cache_only(madera->regmap, false); regcache_cache_only(madera->regmap, false);
regcache_cache_only(madera->regmap_32bit, false); regcache_cache_only(madera->regmap_32bit, false);
usleep_range(MADERA_RESET_MIN_US, MADERA_RESET_MAX_US);
ret = madera_wait_for_boot(madera); ret = madera_wait_for_boot(madera);
if (ret) if (ret)
goto err; goto err;
...@@ -545,6 +552,12 @@ int madera_dev_init(struct madera *madera) ...@@ -545,6 +552,12 @@ int madera_dev_init(struct madera *madera)
regcache_cache_only(madera->regmap, false); regcache_cache_only(madera->regmap, false);
regcache_cache_only(madera->regmap_32bit, false); regcache_cache_only(madera->regmap_32bit, false);
ret = madera_wait_for_boot_noack(madera);
if (ret) {
dev_err(madera->dev, "Device failed initial boot: %d\n", ret);
goto err_reset;
}
/* /*
* Now we can power up and verify that this is a chip we know about * Now we can power up and verify that this is a chip we know about
* before we start doing any writes to its registers. * before we start doing any writes to its registers.
...@@ -650,7 +663,7 @@ int madera_dev_init(struct madera *madera) ...@@ -650,7 +663,7 @@ int madera_dev_init(struct madera *madera)
ret = madera_wait_for_boot(madera); ret = madera_wait_for_boot(madera);
if (ret) { if (ret) {
dev_err(madera->dev, "Device failed initial boot: %d\n", ret); dev_err(madera->dev, "Failed to clear boot done: %d\n", ret);
goto err_reset; goto err_reset;
} }
......
...@@ -26,6 +26,7 @@ static bool rn5t618_volatile_reg(struct device *dev, unsigned int reg) ...@@ -26,6 +26,7 @@ static bool rn5t618_volatile_reg(struct device *dev, unsigned int reg)
case RN5T618_WATCHDOGCNT: case RN5T618_WATCHDOGCNT:
case RN5T618_DCIRQ: case RN5T618_DCIRQ:
case RN5T618_ILIMDATAH ... RN5T618_AIN0DATAL: case RN5T618_ILIMDATAH ... RN5T618_AIN0DATAL:
case RN5T618_ADCCNT3:
case RN5T618_IR_ADC1 ... RN5T618_IR_ADC3: case RN5T618_IR_ADC1 ... RN5T618_IR_ADC3:
case RN5T618_IR_GPR: case RN5T618_IR_GPR:
case RN5T618_IR_GPF: case RN5T618_IR_GPF:
......
...@@ -48,7 +48,7 @@ static struct mfd_cell bd70528_mfd_cells[] = { ...@@ -48,7 +48,7 @@ static struct mfd_cell bd70528_mfd_cells[] = {
* We use BD71837 driver to drive the clock block. Only differences to * We use BD71837 driver to drive the clock block. Only differences to
* BD70528 clock gate are the register address and mask. * BD70528 clock gate are the register address and mask.
*/ */
{ .name = "bd718xx-clk", }, { .name = "bd70528-clk", },
{ .name = "bd70528-wdt", }, { .name = "bd70528-wdt", },
{ {
.name = "bd70528-power", .name = "bd70528-power",
...@@ -236,7 +236,6 @@ static int bd70528_i2c_probe(struct i2c_client *i2c, ...@@ -236,7 +236,6 @@ static int bd70528_i2c_probe(struct i2c_client *i2c,
dev_set_drvdata(&i2c->dev, &bd70528->chip); dev_set_drvdata(&i2c->dev, &bd70528->chip);
bd70528->chip.chip_type = ROHM_CHIP_TYPE_BD70528;
bd70528->chip.regmap = devm_regmap_init_i2c(i2c, &bd70528_regmap); bd70528->chip.regmap = devm_regmap_init_i2c(i2c, &bd70528_regmap);
if (IS_ERR(bd70528->chip.regmap)) { if (IS_ERR(bd70528->chip.regmap)) {
dev_err(&i2c->dev, "Failed to initialize Regmap\n"); dev_err(&i2c->dev, "Failed to initialize Regmap\n");
......
// SPDX-License-Identifier: GPL-2.0-only
//
// Copyright (C) 2019 ROHM Semiconductors
//
// ROHM BD71828 PMIC driver
#include <linux/gpio_keys.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/irq.h>
#include <linux/mfd/core.h>
#include <linux/mfd/rohm-bd71828.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/regmap.h>
#include <linux/types.h>
static struct gpio_keys_button button = {
.code = KEY_POWER,
.gpio = -1,
.type = EV_KEY,
};
static struct gpio_keys_platform_data bd71828_powerkey_data = {
.buttons = &button,
.nbuttons = 1,
.name = "bd71828-pwrkey",
};
static const struct resource rtc_irqs[] = {
DEFINE_RES_IRQ_NAMED(BD71828_INT_RTC0, "bd71828-rtc-alm-0"),
DEFINE_RES_IRQ_NAMED(BD71828_INT_RTC1, "bd71828-rtc-alm-1"),
DEFINE_RES_IRQ_NAMED(BD71828_INT_RTC2, "bd71828-rtc-alm-2"),
};
static struct mfd_cell bd71828_mfd_cells[] = {
{ .name = "bd71828-pmic", },
{ .name = "bd71828-gpio", },
{ .name = "bd71828-led", .of_compatible = "rohm,bd71828-leds" },
/*
* We use BD71837 driver to drive the clock block. Only differences to
* BD70528 clock gate are the register address and mask.
*/
{ .name = "bd71828-clk", },
{ .name = "bd71827-power", },
{
.name = "bd71828-rtc",
.resources = rtc_irqs,
.num_resources = ARRAY_SIZE(rtc_irqs),
}, {
.name = "gpio-keys",
.platform_data = &bd71828_powerkey_data,
.pdata_size = sizeof(bd71828_powerkey_data),
},
};
static const struct regmap_range volatile_ranges[] = {
{
.range_min = BD71828_REG_PS_CTRL_1,
.range_max = BD71828_REG_PS_CTRL_1,
}, {
.range_min = BD71828_REG_PS_CTRL_3,
.range_max = BD71828_REG_PS_CTRL_3,
}, {
.range_min = BD71828_REG_RTC_SEC,
.range_max = BD71828_REG_RTC_YEAR,
}, {
/*
* For now make all charger registers volatile because many
* needs to be and because the charger block is not that
* performance critical.
*/
.range_min = BD71828_REG_CHG_STATE,
.range_max = BD71828_REG_CHG_FULL,
}, {
.range_min = BD71828_REG_INT_MAIN,
.range_max = BD71828_REG_IO_STAT,
},
};
static const struct regmap_access_table volatile_regs = {
.yes_ranges = &volatile_ranges[0],
.n_yes_ranges = ARRAY_SIZE(volatile_ranges),
};
static struct regmap_config bd71828_regmap = {
.reg_bits = 8,
.val_bits = 8,
.volatile_table = &volatile_regs,
.max_register = BD71828_MAX_REGISTER,
.cache_type = REGCACHE_RBTREE,
};
/*
* Mapping of main IRQ register bits to sub-IRQ register offsets so that we can
* access corect sub-IRQ registers based on bits that are set in main IRQ
* register.
*/
static unsigned int bit0_offsets[] = {11}; /* RTC IRQ */
static unsigned int bit1_offsets[] = {10}; /* TEMP IRQ */
static unsigned int bit2_offsets[] = {6, 7, 8, 9}; /* BAT MON IRQ */
static unsigned int bit3_offsets[] = {5}; /* BAT IRQ */
static unsigned int bit4_offsets[] = {4}; /* CHG IRQ */
static unsigned int bit5_offsets[] = {3}; /* VSYS IRQ */
static unsigned int bit6_offsets[] = {1, 2}; /* DCIN IRQ */
static unsigned int bit7_offsets[] = {0}; /* BUCK IRQ */
static struct regmap_irq_sub_irq_map bd71828_sub_irq_offsets[] = {
REGMAP_IRQ_MAIN_REG_OFFSET(bit0_offsets),
REGMAP_IRQ_MAIN_REG_OFFSET(bit1_offsets),
REGMAP_IRQ_MAIN_REG_OFFSET(bit2_offsets),
REGMAP_IRQ_MAIN_REG_OFFSET(bit3_offsets),
REGMAP_IRQ_MAIN_REG_OFFSET(bit4_offsets),
REGMAP_IRQ_MAIN_REG_OFFSET(bit5_offsets),
REGMAP_IRQ_MAIN_REG_OFFSET(bit6_offsets),
REGMAP_IRQ_MAIN_REG_OFFSET(bit7_offsets),
};
static struct regmap_irq bd71828_irqs[] = {
REGMAP_IRQ_REG(BD71828_INT_BUCK1_OCP, 0, BD71828_INT_BUCK1_OCP_MASK),
REGMAP_IRQ_REG(BD71828_INT_BUCK2_OCP, 0, BD71828_INT_BUCK2_OCP_MASK),
REGMAP_IRQ_REG(BD71828_INT_BUCK3_OCP, 0, BD71828_INT_BUCK3_OCP_MASK),
REGMAP_IRQ_REG(BD71828_INT_BUCK4_OCP, 0, BD71828_INT_BUCK4_OCP_MASK),
REGMAP_IRQ_REG(BD71828_INT_BUCK5_OCP, 0, BD71828_INT_BUCK5_OCP_MASK),
REGMAP_IRQ_REG(BD71828_INT_BUCK6_OCP, 0, BD71828_INT_BUCK6_OCP_MASK),
REGMAP_IRQ_REG(BD71828_INT_BUCK7_OCP, 0, BD71828_INT_BUCK7_OCP_MASK),
REGMAP_IRQ_REG(BD71828_INT_PGFAULT, 0, BD71828_INT_PGFAULT_MASK),
/* DCIN1 interrupts */
REGMAP_IRQ_REG(BD71828_INT_DCIN_DET, 1, BD71828_INT_DCIN_DET_MASK),
REGMAP_IRQ_REG(BD71828_INT_DCIN_RMV, 1, BD71828_INT_DCIN_RMV_MASK),
REGMAP_IRQ_REG(BD71828_INT_CLPS_OUT, 1, BD71828_INT_CLPS_OUT_MASK),
REGMAP_IRQ_REG(BD71828_INT_CLPS_IN, 1, BD71828_INT_CLPS_IN_MASK),
/* DCIN2 interrupts */
REGMAP_IRQ_REG(BD71828_INT_DCIN_MON_RES, 2,
BD71828_INT_DCIN_MON_RES_MASK),
REGMAP_IRQ_REG(BD71828_INT_DCIN_MON_DET, 2,
BD71828_INT_DCIN_MON_DET_MASK),
REGMAP_IRQ_REG(BD71828_INT_LONGPUSH, 2, BD71828_INT_LONGPUSH_MASK),
REGMAP_IRQ_REG(BD71828_INT_MIDPUSH, 2, BD71828_INT_MIDPUSH_MASK),
REGMAP_IRQ_REG(BD71828_INT_SHORTPUSH, 2, BD71828_INT_SHORTPUSH_MASK),
REGMAP_IRQ_REG(BD71828_INT_PUSH, 2, BD71828_INT_PUSH_MASK),
REGMAP_IRQ_REG(BD71828_INT_WDOG, 2, BD71828_INT_WDOG_MASK),
REGMAP_IRQ_REG(BD71828_INT_SWRESET, 2, BD71828_INT_SWRESET_MASK),
/* Vsys */
REGMAP_IRQ_REG(BD71828_INT_VSYS_UV_RES, 3,
BD71828_INT_VSYS_UV_RES_MASK),
REGMAP_IRQ_REG(BD71828_INT_VSYS_UV_DET, 3,
BD71828_INT_VSYS_UV_DET_MASK),
REGMAP_IRQ_REG(BD71828_INT_VSYS_LOW_RES, 3,
BD71828_INT_VSYS_LOW_RES_MASK),
REGMAP_IRQ_REG(BD71828_INT_VSYS_LOW_DET, 3,
BD71828_INT_VSYS_LOW_DET_MASK),
REGMAP_IRQ_REG(BD71828_INT_VSYS_HALL_IN, 3,
BD71828_INT_VSYS_HALL_IN_MASK),
REGMAP_IRQ_REG(BD71828_INT_VSYS_HALL_TOGGLE, 3,
BD71828_INT_VSYS_HALL_TOGGLE_MASK),
REGMAP_IRQ_REG(BD71828_INT_VSYS_MON_RES, 3,
BD71828_INT_VSYS_MON_RES_MASK),
REGMAP_IRQ_REG(BD71828_INT_VSYS_MON_DET, 3,
BD71828_INT_VSYS_MON_DET_MASK),
/* Charger */
REGMAP_IRQ_REG(BD71828_INT_CHG_DCIN_ILIM, 4,
BD71828_INT_CHG_DCIN_ILIM_MASK),
REGMAP_IRQ_REG(BD71828_INT_CHG_TOPOFF_TO_DONE, 4,
BD71828_INT_CHG_TOPOFF_TO_DONE_MASK),
REGMAP_IRQ_REG(BD71828_INT_CHG_WDG_TEMP, 4,
BD71828_INT_CHG_WDG_TEMP_MASK),
REGMAP_IRQ_REG(BD71828_INT_CHG_WDG_TIME, 4,
BD71828_INT_CHG_WDG_TIME_MASK),
REGMAP_IRQ_REG(BD71828_INT_CHG_RECHARGE_RES, 4,
BD71828_INT_CHG_RECHARGE_RES_MASK),
REGMAP_IRQ_REG(BD71828_INT_CHG_RECHARGE_DET, 4,
BD71828_INT_CHG_RECHARGE_DET_MASK),
REGMAP_IRQ_REG(BD71828_INT_CHG_RANGED_TEMP_TRANSITION, 4,
BD71828_INT_CHG_RANGED_TEMP_TRANSITION_MASK),
REGMAP_IRQ_REG(BD71828_INT_CHG_STATE_TRANSITION, 4,
BD71828_INT_CHG_STATE_TRANSITION_MASK),
/* Battery */
REGMAP_IRQ_REG(BD71828_INT_BAT_TEMP_NORMAL, 5,
BD71828_INT_BAT_TEMP_NORMAL_MASK),
REGMAP_IRQ_REG(BD71828_INT_BAT_TEMP_ERANGE, 5,
BD71828_INT_BAT_TEMP_ERANGE_MASK),
REGMAP_IRQ_REG(BD71828_INT_BAT_TEMP_WARN, 5,
BD71828_INT_BAT_TEMP_WARN_MASK),
REGMAP_IRQ_REG(BD71828_INT_BAT_REMOVED, 5,
BD71828_INT_BAT_REMOVED_MASK),
REGMAP_IRQ_REG(BD71828_INT_BAT_DETECTED, 5,
BD71828_INT_BAT_DETECTED_MASK),
REGMAP_IRQ_REG(BD71828_INT_THERM_REMOVED, 5,
BD71828_INT_THERM_REMOVED_MASK),
REGMAP_IRQ_REG(BD71828_INT_THERM_DETECTED, 5,
BD71828_INT_THERM_DETECTED_MASK),
/* Battery Mon 1 */
REGMAP_IRQ_REG(BD71828_INT_BAT_DEAD, 6, BD71828_INT_BAT_DEAD_MASK),
REGMAP_IRQ_REG(BD71828_INT_BAT_SHORTC_RES, 6,
BD71828_INT_BAT_SHORTC_RES_MASK),
REGMAP_IRQ_REG(BD71828_INT_BAT_SHORTC_DET, 6,
BD71828_INT_BAT_SHORTC_DET_MASK),
REGMAP_IRQ_REG(BD71828_INT_BAT_LOW_VOLT_RES, 6,
BD71828_INT_BAT_LOW_VOLT_RES_MASK),
REGMAP_IRQ_REG(BD71828_INT_BAT_LOW_VOLT_DET, 6,
BD71828_INT_BAT_LOW_VOLT_DET_MASK),
REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_VOLT_RES, 6,
BD71828_INT_BAT_OVER_VOLT_RES_MASK),
REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_VOLT_DET, 6,
BD71828_INT_BAT_OVER_VOLT_DET_MASK),
/* Battery Mon 2 */
REGMAP_IRQ_REG(BD71828_INT_BAT_MON_RES, 7,
BD71828_INT_BAT_MON_RES_MASK),
REGMAP_IRQ_REG(BD71828_INT_BAT_MON_DET, 7,
BD71828_INT_BAT_MON_DET_MASK),
/* Battery Mon 3 (Coulomb counter) */
REGMAP_IRQ_REG(BD71828_INT_BAT_CC_MON1, 8,
BD71828_INT_BAT_CC_MON1_MASK),
REGMAP_IRQ_REG(BD71828_INT_BAT_CC_MON2, 8,
BD71828_INT_BAT_CC_MON2_MASK),
REGMAP_IRQ_REG(BD71828_INT_BAT_CC_MON3, 8,
BD71828_INT_BAT_CC_MON3_MASK),
/* Battery Mon 4 */
REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_1_RES, 9,
BD71828_INT_BAT_OVER_CURR_1_RES_MASK),
REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_1_DET, 9,
BD71828_INT_BAT_OVER_CURR_1_DET_MASK),
REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_2_RES, 9,
BD71828_INT_BAT_OVER_CURR_2_RES_MASK),
REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_2_DET, 9,
BD71828_INT_BAT_OVER_CURR_2_DET_MASK),
REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_3_RES, 9,
BD71828_INT_BAT_OVER_CURR_3_RES_MASK),
REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_3_DET, 9,
BD71828_INT_BAT_OVER_CURR_3_DET_MASK),
/* Temperature */
REGMAP_IRQ_REG(BD71828_INT_TEMP_BAT_LOW_RES, 10,
BD71828_INT_TEMP_BAT_LOW_RES_MASK),
REGMAP_IRQ_REG(BD71828_INT_TEMP_BAT_LOW_DET, 10,
BD71828_INT_TEMP_BAT_LOW_DET_MASK),
REGMAP_IRQ_REG(BD71828_INT_TEMP_BAT_HI_RES, 10,
BD71828_INT_TEMP_BAT_HI_RES_MASK),
REGMAP_IRQ_REG(BD71828_INT_TEMP_BAT_HI_DET, 10,
BD71828_INT_TEMP_BAT_HI_DET_MASK),
REGMAP_IRQ_REG(BD71828_INT_TEMP_CHIP_OVER_125_RES, 10,
BD71828_INT_TEMP_CHIP_OVER_125_RES_MASK),
REGMAP_IRQ_REG(BD71828_INT_TEMP_CHIP_OVER_125_DET, 10,
BD71828_INT_TEMP_CHIP_OVER_125_DET_MASK),
REGMAP_IRQ_REG(BD71828_INT_TEMP_CHIP_OVER_VF_DET, 10,
BD71828_INT_TEMP_CHIP_OVER_VF_DET_MASK),
REGMAP_IRQ_REG(BD71828_INT_TEMP_CHIP_OVER_VF_RES, 10,
BD71828_INT_TEMP_CHIP_OVER_VF_RES_MASK),
/* RTC Alarm */
REGMAP_IRQ_REG(BD71828_INT_RTC0, 11, BD71828_INT_RTC0_MASK),
REGMAP_IRQ_REG(BD71828_INT_RTC1, 11, BD71828_INT_RTC1_MASK),
REGMAP_IRQ_REG(BD71828_INT_RTC2, 11, BD71828_INT_RTC2_MASK),
};
static struct regmap_irq_chip bd71828_irq_chip = {
.name = "bd71828_irq",
.main_status = BD71828_REG_INT_MAIN,
.irqs = &bd71828_irqs[0],
.num_irqs = ARRAY_SIZE(bd71828_irqs),
.status_base = BD71828_REG_INT_BUCK,
.mask_base = BD71828_REG_INT_MASK_BUCK,
.ack_base = BD71828_REG_INT_BUCK,
.mask_invert = true,
.init_ack_masked = true,
.num_regs = 12,
.num_main_regs = 1,
.sub_reg_offsets = &bd71828_sub_irq_offsets[0],
.num_main_status_bits = 8,
.irq_reg_stride = 1,
};
static int bd71828_i2c_probe(struct i2c_client *i2c)
{
struct rohm_regmap_dev *chip;
struct regmap_irq_chip_data *irq_data;
int ret;
if (!i2c->irq) {
dev_err(&i2c->dev, "No IRQ configured\n");
return -EINVAL;
}
chip = devm_kzalloc(&i2c->dev, sizeof(*chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;
dev_set_drvdata(&i2c->dev, chip);
chip->regmap = devm_regmap_init_i2c(i2c, &bd71828_regmap);
if (IS_ERR(chip->regmap)) {
dev_err(&i2c->dev, "Failed to initialize Regmap\n");
return PTR_ERR(chip->regmap);
}
ret = devm_regmap_add_irq_chip(&i2c->dev, chip->regmap,
i2c->irq, IRQF_ONESHOT, 0,
&bd71828_irq_chip, &irq_data);
if (ret) {
dev_err(&i2c->dev, "Failed to add IRQ chip\n");
return ret;
}
dev_dbg(&i2c->dev, "Registered %d IRQs for chip\n",
bd71828_irq_chip.num_irqs);
ret = regmap_irq_get_virq(irq_data, BD71828_INT_SHORTPUSH);
if (ret < 0) {
dev_err(&i2c->dev, "Failed to get the power-key IRQ\n");
return ret;
}
button.irq = ret;
ret = devm_mfd_add_devices(&i2c->dev, PLATFORM_DEVID_AUTO,
bd71828_mfd_cells,
ARRAY_SIZE(bd71828_mfd_cells), NULL, 0,
regmap_irq_get_domain(irq_data));
if (ret)
dev_err(&i2c->dev, "Failed to create subdevices\n");
return ret;
}
static const struct of_device_id bd71828_of_match[] = {
{ .compatible = "rohm,bd71828", },
{ },
};
MODULE_DEVICE_TABLE(of, bd71828_of_match);
static struct i2c_driver bd71828_drv = {
.driver = {
.name = "rohm-bd71828",
.of_match_table = bd71828_of_match,
},
.probe_new = &bd71828_i2c_probe,
};
module_i2c_driver(bd71828_drv);
MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
MODULE_DESCRIPTION("ROHM BD71828 Power Management IC driver");
MODULE_LICENSE("GPL");
...@@ -30,14 +30,24 @@ static struct gpio_keys_platform_data bd718xx_powerkey_data = { ...@@ -30,14 +30,24 @@ static struct gpio_keys_platform_data bd718xx_powerkey_data = {
.name = "bd718xx-pwrkey", .name = "bd718xx-pwrkey",
}; };
static struct mfd_cell bd718xx_mfd_cells[] = { static struct mfd_cell bd71837_mfd_cells[] = {
{ {
.name = "gpio-keys", .name = "gpio-keys",
.platform_data = &bd718xx_powerkey_data, .platform_data = &bd718xx_powerkey_data,
.pdata_size = sizeof(bd718xx_powerkey_data), .pdata_size = sizeof(bd718xx_powerkey_data),
}, },
{ .name = "bd718xx-clk", }, { .name = "bd71837-clk", },
{ .name = "bd718xx-pmic", }, { .name = "bd71837-pmic", },
};
static struct mfd_cell bd71847_mfd_cells[] = {
{
.name = "gpio-keys",
.platform_data = &bd718xx_powerkey_data,
.pdata_size = sizeof(bd718xx_powerkey_data),
},
{ .name = "bd71847-clk", },
{ .name = "bd71847-pmic", },
}; };
static const struct regmap_irq bd718xx_irqs[] = { static const struct regmap_irq bd718xx_irqs[] = {
...@@ -124,6 +134,9 @@ static int bd718xx_i2c_probe(struct i2c_client *i2c, ...@@ -124,6 +134,9 @@ static int bd718xx_i2c_probe(struct i2c_client *i2c,
{ {
struct bd718xx *bd718xx; struct bd718xx *bd718xx;
int ret; int ret;
unsigned int chip_type;
struct mfd_cell *mfd;
int cells;
if (!i2c->irq) { if (!i2c->irq) {
dev_err(&i2c->dev, "No IRQ configured\n"); dev_err(&i2c->dev, "No IRQ configured\n");
...@@ -136,8 +149,21 @@ static int bd718xx_i2c_probe(struct i2c_client *i2c, ...@@ -136,8 +149,21 @@ static int bd718xx_i2c_probe(struct i2c_client *i2c,
return -ENOMEM; return -ENOMEM;
bd718xx->chip_irq = i2c->irq; bd718xx->chip_irq = i2c->irq;
bd718xx->chip.chip_type = (unsigned int)(uintptr_t) chip_type = (unsigned int)(uintptr_t)
of_device_get_match_data(&i2c->dev); of_device_get_match_data(&i2c->dev);
switch (chip_type) {
case ROHM_CHIP_TYPE_BD71837:
mfd = bd71837_mfd_cells;
cells = ARRAY_SIZE(bd71837_mfd_cells);
break;
case ROHM_CHIP_TYPE_BD71847:
mfd = bd71847_mfd_cells;
cells = ARRAY_SIZE(bd71847_mfd_cells);
break;
default:
dev_err(&i2c->dev, "Unknown device type");
return -EINVAL;
}
bd718xx->chip.dev = &i2c->dev; bd718xx->chip.dev = &i2c->dev;
dev_set_drvdata(&i2c->dev, bd718xx); dev_set_drvdata(&i2c->dev, bd718xx);
...@@ -170,8 +196,7 @@ static int bd718xx_i2c_probe(struct i2c_client *i2c, ...@@ -170,8 +196,7 @@ static int bd718xx_i2c_probe(struct i2c_client *i2c,
button.irq = ret; button.irq = ret;
ret = devm_mfd_add_devices(bd718xx->chip.dev, PLATFORM_DEVID_AUTO, ret = devm_mfd_add_devices(bd718xx->chip.dev, PLATFORM_DEVID_AUTO,
bd718xx_mfd_cells, mfd, cells, NULL, 0,
ARRAY_SIZE(bd718xx_mfd_cells), NULL, 0,
regmap_irq_get_domain(bd718xx->irq_data)); regmap_irq_get_domain(bd718xx->irq_data));
if (ret) if (ret)
dev_err(&i2c->dev, "Failed to create subdevices\n"); dev_err(&i2c->dev, "Failed to create subdevices\n");
...@@ -188,6 +213,10 @@ static const struct of_device_id bd718xx_of_match[] = { ...@@ -188,6 +213,10 @@ static const struct of_device_id bd718xx_of_match[] = {
.compatible = "rohm,bd71847", .compatible = "rohm,bd71847",
.data = (void *)ROHM_CHIP_TYPE_BD71847, .data = (void *)ROHM_CHIP_TYPE_BD71847,
}, },
{
.compatible = "rohm,bd71850",
.data = (void *)ROHM_CHIP_TYPE_BD71847,
},
{ } { }
}; };
MODULE_DEVICE_TABLE(of, bd718xx_of_match); MODULE_DEVICE_TABLE(of, bd718xx_of_match);
......
...@@ -1086,8 +1086,7 @@ static int sm501_register_gpio(struct sm501_devdata *sm) ...@@ -1086,8 +1086,7 @@ static int sm501_register_gpio(struct sm501_devdata *sm)
iounmap(gpio->regs); iounmap(gpio->regs);
err_claimed: err_claimed:
release_resource(gpio->regs_res); release_mem_region(iobase, 0x20);
kfree(gpio->regs_res);
return ret; return ret;
} }
...@@ -1095,6 +1094,7 @@ static int sm501_register_gpio(struct sm501_devdata *sm) ...@@ -1095,6 +1094,7 @@ static int sm501_register_gpio(struct sm501_devdata *sm)
static void sm501_gpio_remove(struct sm501_devdata *sm) static void sm501_gpio_remove(struct sm501_devdata *sm)
{ {
struct sm501_gpio *gpio = &sm->gpio; struct sm501_gpio *gpio = &sm->gpio;
resource_size_t iobase = sm->io_res->start + SM501_GPIO;
if (!sm->gpio.registered) if (!sm->gpio.registered)
return; return;
...@@ -1103,8 +1103,7 @@ static void sm501_gpio_remove(struct sm501_devdata *sm) ...@@ -1103,8 +1103,7 @@ static void sm501_gpio_remove(struct sm501_devdata *sm)
gpiochip_remove(&gpio->high.gpio); gpiochip_remove(&gpio->high.gpio);
iounmap(gpio->regs); iounmap(gpio->regs);
release_resource(gpio->regs_res); release_mem_region(iobase, 0x20);
kfree(gpio->regs_res);
} }
static inline int sm501_gpio_isregistered(struct sm501_devdata *sm) static inline int sm501_gpio_isregistered(struct sm501_devdata *sm)
...@@ -1427,8 +1426,7 @@ static int sm501_plat_probe(struct platform_device *dev) ...@@ -1427,8 +1426,7 @@ static int sm501_plat_probe(struct platform_device *dev)
return sm501_init_dev(sm); return sm501_init_dev(sm);
err_claim: err_claim:
release_resource(sm->regs_claim); release_mem_region(sm->io_res->start, 0x100);
kfree(sm->regs_claim);
err_res: err_res:
kfree(sm); kfree(sm);
err1: err1:
...@@ -1637,8 +1635,7 @@ static int sm501_pci_probe(struct pci_dev *dev, ...@@ -1637,8 +1635,7 @@ static int sm501_pci_probe(struct pci_dev *dev,
return 0; return 0;
err4: err4:
release_resource(sm->regs_claim); release_mem_region(sm->io_res->start, 0x100);
kfree(sm->regs_claim);
err3: err3:
pci_disable_device(dev); pci_disable_device(dev);
err2: err2:
...@@ -1673,8 +1670,7 @@ static void sm501_pci_remove(struct pci_dev *dev) ...@@ -1673,8 +1670,7 @@ static void sm501_pci_remove(struct pci_dev *dev)
sm501_dev_remove(sm); sm501_dev_remove(sm);
iounmap(sm->regs); iounmap(sm->regs);
release_resource(sm->regs_claim); release_mem_region(sm->io_res->start, 0x100);
kfree(sm->regs_claim);
pci_disable_device(dev); pci_disable_device(dev);
} }
...@@ -1686,8 +1682,7 @@ static int sm501_plat_remove(struct platform_device *dev) ...@@ -1686,8 +1682,7 @@ static int sm501_plat_remove(struct platform_device *dev)
sm501_dev_remove(sm); sm501_dev_remove(sm);
iounmap(sm->regs); iounmap(sm->regs);
release_resource(sm->regs_claim); release_mem_region(sm->io_res->start, 0x100);
kfree(sm->regs_claim);
return 0; return 0;
} }
......
...@@ -224,6 +224,35 @@ struct regmap *syscon_regmap_lookup_by_phandle(struct device_node *np, ...@@ -224,6 +224,35 @@ struct regmap *syscon_regmap_lookup_by_phandle(struct device_node *np,
} }
EXPORT_SYMBOL_GPL(syscon_regmap_lookup_by_phandle); EXPORT_SYMBOL_GPL(syscon_regmap_lookup_by_phandle);
struct regmap *syscon_regmap_lookup_by_phandle_args(struct device_node *np,
const char *property,
int arg_count,
unsigned int *out_args)
{
struct device_node *syscon_np;
struct of_phandle_args args;
struct regmap *regmap;
unsigned int index;
int rc;
rc = of_parse_phandle_with_fixed_args(np, property, arg_count,
0, &args);
if (rc)
return ERR_PTR(rc);
syscon_np = args.np;
if (!syscon_np)
return ERR_PTR(-ENODEV);
regmap = syscon_node_to_regmap(syscon_np);
for (index = 0; index < arg_count; index++)
out_args[index] = args.args[index];
of_node_put(syscon_np);
return regmap;
}
EXPORT_SYMBOL_GPL(syscon_regmap_lookup_by_phandle_args);
static int syscon_probe(struct platform_device *pdev) static int syscon_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
...@@ -245,7 +274,7 @@ static int syscon_probe(struct platform_device *pdev) ...@@ -245,7 +274,7 @@ static int syscon_probe(struct platform_device *pdev)
if (!base) if (!base)
return -ENOMEM; return -ENOMEM;
syscon_config.max_register = res->end - res->start - 3; syscon_config.max_register = resource_size(res) - 4;
if (pdata) if (pdata)
syscon_config.name = pdata->label; syscon_config.name = pdata->label;
syscon->regmap = devm_regmap_init_mmio(dev, base, &syscon_config); syscon->regmap = devm_regmap_init_mmio(dev, base, &syscon_config);
......
...@@ -158,7 +158,7 @@ static int tqmx86_board_id_to_clk_rate(u8 board_id) ...@@ -158,7 +158,7 @@ static int tqmx86_board_id_to_clk_rate(u8 board_id)
static int tqmx86_probe(struct platform_device *pdev) static int tqmx86_probe(struct platform_device *pdev)
{ {
u8 board_id, rev, i2c_det, i2c_ien, io_ext_int_val; u8 board_id, rev, i2c_det, io_ext_int_val;
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
u8 gpio_irq_cfg, readback; u8 gpio_irq_cfg, readback;
const char *board_name; const char *board_name;
...@@ -196,7 +196,6 @@ static int tqmx86_probe(struct platform_device *pdev) ...@@ -196,7 +196,6 @@ static int tqmx86_probe(struct platform_device *pdev)
board_name, board_id, rev >> 4, rev & 0xf); board_name, board_id, rev >> 4, rev & 0xf);
i2c_det = ioread8(io_base + TQMX86_REG_I2C_DETECT); i2c_det = ioread8(io_base + TQMX86_REG_I2C_DETECT);
i2c_ien = ioread8(io_base + TQMX86_REG_I2C_INT_EN);
if (gpio_irq_cfg) { if (gpio_irq_cfg) {
io_ext_int_val = io_ext_int_val =
......
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2019, Linaro Limited
#include <linux/clk.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/mfd/core.h>
#include <linux/mfd/wcd934x/registers.h>
#include <linux/mfd/wcd934x/wcd934x.h>
#include <linux/module.h>
#include <linux/of_gpio.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/slimbus.h>
static const struct mfd_cell wcd934x_devices[] = {
{
.name = "wcd934x-codec",
}, {
.name = "wcd934x-gpio",
.of_compatible = "qcom,wcd9340-gpio",
}, {
.name = "wcd934x-soundwire",
.of_compatible = "qcom,soundwire-v1.3.0",
},
};
static const struct regmap_irq wcd934x_irqs[] = {
[WCD934X_IRQ_SLIMBUS] = {
.reg_offset = 0,
.mask = BIT(0),
.type = {
.type_reg_offset = 0,
.types_supported = IRQ_TYPE_EDGE_BOTH,
.type_reg_mask = BIT(0),
.type_level_low_val = BIT(0),
.type_level_high_val = BIT(0),
.type_falling_val = 0,
.type_rising_val = 0,
},
},
[WCD934X_IRQ_SOUNDWIRE] = {
.reg_offset = 2,
.mask = BIT(4),
.type = {
.type_reg_offset = 2,
.types_supported = IRQ_TYPE_EDGE_BOTH,
.type_reg_mask = BIT(4),
.type_level_low_val = BIT(4),
.type_level_high_val = BIT(4),
.type_falling_val = 0,
.type_rising_val = 0,
},
},
};
static const struct regmap_irq_chip wcd934x_regmap_irq_chip = {
.name = "wcd934x_irq",
.status_base = WCD934X_INTR_PIN1_STATUS0,
.mask_base = WCD934X_INTR_PIN1_MASK0,
.ack_base = WCD934X_INTR_PIN1_CLEAR0,
.type_base = WCD934X_INTR_LEVEL0,
.num_type_reg = 4,
.type_in_mask = false,
.num_regs = 4,
.irqs = wcd934x_irqs,
.num_irqs = ARRAY_SIZE(wcd934x_irqs),
};
static bool wcd934x_is_volatile_register(struct device *dev, unsigned int reg)
{
switch (reg) {
case WCD934X_INTR_PIN1_STATUS0...WCD934X_INTR_PIN2_CLEAR3:
case WCD934X_SWR_AHB_BRIDGE_RD_DATA_0:
case WCD934X_SWR_AHB_BRIDGE_RD_DATA_1:
case WCD934X_SWR_AHB_BRIDGE_RD_DATA_2:
case WCD934X_SWR_AHB_BRIDGE_RD_DATA_3:
case WCD934X_SWR_AHB_BRIDGE_ACCESS_STATUS:
case WCD934X_ANA_MBHC_RESULT_3:
case WCD934X_ANA_MBHC_RESULT_2:
case WCD934X_ANA_MBHC_RESULT_1:
case WCD934X_ANA_MBHC_MECH:
case WCD934X_ANA_MBHC_ELECT:
case WCD934X_ANA_MBHC_ZDET:
case WCD934X_ANA_MICB2:
case WCD934X_ANA_RCO:
case WCD934X_ANA_BIAS:
return true;
default:
return false;
}
};
static const struct regmap_range_cfg wcd934x_ranges[] = {
{ .name = "WCD934X",
.range_min = 0x0,
.range_max = WCD934X_MAX_REGISTER,
.selector_reg = WCD934X_SEL_REGISTER,
.selector_mask = WCD934X_SEL_MASK,
.selector_shift = WCD934X_SEL_SHIFT,
.window_start = WCD934X_WINDOW_START,
.window_len = WCD934X_WINDOW_LENGTH,
},
};
static struct regmap_config wcd934x_regmap_config = {
.reg_bits = 16,
.val_bits = 8,
.cache_type = REGCACHE_RBTREE,
.max_register = 0xffff,
.can_multi_write = true,
.ranges = wcd934x_ranges,
.num_ranges = ARRAY_SIZE(wcd934x_ranges),
.volatile_reg = wcd934x_is_volatile_register,
};
static int wcd934x_bring_up(struct wcd934x_ddata *ddata)
{
struct regmap *regmap = ddata->regmap;
u16 id_minor, id_major;
int ret;
ret = regmap_bulk_read(regmap, WCD934X_CHIP_TIER_CTRL_CHIP_ID_BYTE0,
(u8 *)&id_minor, sizeof(u16));
if (ret)
return ret;
ret = regmap_bulk_read(regmap, WCD934X_CHIP_TIER_CTRL_CHIP_ID_BYTE2,
(u8 *)&id_major, sizeof(u16));
if (ret)
return ret;
dev_info(ddata->dev, "WCD934x chip id major 0x%x, minor 0x%x\n",
id_major, id_minor);
regmap_write(regmap, WCD934X_CODEC_RPM_RST_CTL, 0x01);
regmap_write(regmap, WCD934X_SIDO_NEW_VOUT_A_STARTUP, 0x19);
regmap_write(regmap, WCD934X_SIDO_NEW_VOUT_D_STARTUP, 0x15);
/* Add 1msec delay for VOUT to settle */
usleep_range(1000, 1100);
regmap_write(regmap, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x5);
regmap_write(regmap, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x7);
regmap_write(regmap, WCD934X_CODEC_RPM_RST_CTL, 0x3);
regmap_write(regmap, WCD934X_CODEC_RPM_RST_CTL, 0x7);
regmap_write(regmap, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x3);
return 0;
}
static int wcd934x_slim_status_up(struct slim_device *sdev)
{
struct device *dev = &sdev->dev;
struct wcd934x_ddata *ddata;
int ret;
ddata = dev_get_drvdata(dev);
ddata->regmap = regmap_init_slimbus(sdev, &wcd934x_regmap_config);
if (IS_ERR(ddata->regmap)) {
dev_err(dev, "Error allocating slim regmap\n");
return PTR_ERR(ddata->regmap);
}
ret = wcd934x_bring_up(ddata);
if (ret) {
dev_err(dev, "Failed to bring up WCD934X: err = %d\n", ret);
return ret;
}
ret = devm_regmap_add_irq_chip(dev, ddata->regmap, ddata->irq,
IRQF_TRIGGER_HIGH, 0,
&wcd934x_regmap_irq_chip,
&ddata->irq_data);
if (ret) {
dev_err(dev, "Failed to add IRQ chip: err = %d\n", ret);
return ret;
}
ret = mfd_add_devices(dev, PLATFORM_DEVID_AUTO, wcd934x_devices,
ARRAY_SIZE(wcd934x_devices), NULL, 0, NULL);
if (ret) {
dev_err(dev, "Failed to add child devices: err = %d\n",
ret);
return ret;
}
return ret;
}
static int wcd934x_slim_status(struct slim_device *sdev,
enum slim_device_status status)
{
switch (status) {
case SLIM_DEVICE_STATUS_UP:
return wcd934x_slim_status_up(sdev);
case SLIM_DEVICE_STATUS_DOWN:
mfd_remove_devices(&sdev->dev);
break;
default:
return -EINVAL;
}
return 0;
}
static int wcd934x_slim_probe(struct slim_device *sdev)
{
struct device *dev = &sdev->dev;
struct device_node *np = dev->of_node;
struct wcd934x_ddata *ddata;
int reset_gpio, ret;
ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL);
if (!ddata)
return -ENOMEM;
ddata->irq = of_irq_get(np, 0);
if (ddata->irq < 0) {
if (ddata->irq != -EPROBE_DEFER)
dev_err(ddata->dev, "Failed to get IRQ: err = %d\n",
ddata->irq);
return ddata->irq;
}
reset_gpio = of_get_named_gpio(np, "reset-gpios", 0);
if (reset_gpio < 0) {
dev_err(dev, "Failed to get reset gpio: err = %d\n",
reset_gpio);
return reset_gpio;
}
ddata->extclk = devm_clk_get(dev, "extclk");
if (IS_ERR(ddata->extclk)) {
dev_err(dev, "Failed to get extclk");
return PTR_ERR(ddata->extclk);
}
ddata->supplies[0].supply = "vdd-buck";
ddata->supplies[1].supply = "vdd-buck-sido";
ddata->supplies[2].supply = "vdd-tx";
ddata->supplies[3].supply = "vdd-rx";
ddata->supplies[4].supply = "vdd-io";
ret = regulator_bulk_get(dev, WCD934X_MAX_SUPPLY, ddata->supplies);
if (ret) {
dev_err(dev, "Failed to get supplies: err = %d\n", ret);
return ret;
}
ret = regulator_bulk_enable(WCD934X_MAX_SUPPLY, ddata->supplies);
if (ret) {
dev_err(dev, "Failed to enable supplies: err = %d\n", ret);
return ret;
}
/*
* For WCD934X, it takes about 600us for the Vout_A and
* Vout_D to be ready after BUCK_SIDO is powered up.
* SYS_RST_N shouldn't be pulled high during this time
*/
usleep_range(600, 650);
gpio_direction_output(reset_gpio, 0);
msleep(20);
gpio_set_value(reset_gpio, 1);
msleep(20);
ddata->dev = dev;
dev_set_drvdata(dev, ddata);
return 0;
}
static void wcd934x_slim_remove(struct slim_device *sdev)
{
struct wcd934x_ddata *ddata = dev_get_drvdata(&sdev->dev);
regulator_bulk_disable(WCD934X_MAX_SUPPLY, ddata->supplies);
mfd_remove_devices(&sdev->dev);
kfree(ddata);
}
static const struct slim_device_id wcd934x_slim_id[] = {
{ SLIM_MANF_ID_QCOM, SLIM_PROD_CODE_WCD9340,
SLIM_DEV_IDX_WCD9340, SLIM_DEV_INSTANCE_ID_WCD9340 },
{}
};
static struct slim_driver wcd934x_slim_driver = {
.driver = {
.name = "wcd934x-slim",
},
.probe = wcd934x_slim_probe,
.remove = wcd934x_slim_remove,
.device_status = wcd934x_slim_status,
.id_table = wcd934x_slim_id,
};
module_slim_driver(wcd934x_slim_driver);
MODULE_DESCRIPTION("WCD934X slim driver");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("slim:217:250:*");
MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org>");
...@@ -209,6 +209,7 @@ config REGULATOR_BD71828 ...@@ -209,6 +209,7 @@ config REGULATOR_BD71828
config REGULATOR_BD718XX config REGULATOR_BD718XX
tristate "ROHM BD71837 Power Regulator" tristate "ROHM BD71837 Power Regulator"
depends on MFD_ROHM_BD718XX depends on MFD_ROHM_BD718XX
select REGULATOR_ROHM
help help
This driver supports voltage regulators on ROHM BD71837 PMIC. This driver supports voltage regulators on ROHM BD71837 PMIC.
This will enable support for the software controllable buck This will enable support for the software controllable buck
...@@ -823,6 +824,9 @@ config REGULATOR_RN5T618 ...@@ -823,6 +824,9 @@ config REGULATOR_RN5T618
Say y here to support the regulators found on Ricoh RN5T567, Say y here to support the regulators found on Ricoh RN5T567,
RN5T618 or RC5T619 PMIC. RN5T618 or RC5T619 PMIC.
config REGULATOR_ROHM
tristate
config REGULATOR_RT5033 config REGULATOR_RT5033
tristate "Richtek RT5033 Regulators" tristate "Richtek RT5033 Regulators"
depends on MFD_RT5033 depends on MFD_RT5033
......
...@@ -102,6 +102,7 @@ obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o ...@@ -102,6 +102,7 @@ obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o
obj-$(CONFIG_REGULATOR_RC5T583) += rc5t583-regulator.o obj-$(CONFIG_REGULATOR_RC5T583) += rc5t583-regulator.o
obj-$(CONFIG_REGULATOR_RK808) += rk808-regulator.o obj-$(CONFIG_REGULATOR_RK808) += rk808-regulator.o
obj-$(CONFIG_REGULATOR_RN5T618) += rn5t618-regulator.o obj-$(CONFIG_REGULATOR_RN5T618) += rn5t618-regulator.o
obj-$(CONFIG_REGULATOR_ROHM) += rohm-regulator.o
obj-$(CONFIG_REGULATOR_RT5033) += rt5033-regulator.o obj-$(CONFIG_REGULATOR_RT5033) += rt5033-regulator.o
obj-$(CONFIG_REGULATOR_S2MPA01) += s2mpa01.o obj-$(CONFIG_REGULATOR_S2MPA01) += s2mpa01.o
obj-$(CONFIG_REGULATOR_S2MPS11) += s2mps11.o obj-$(CONFIG_REGULATOR_S2MPS11) += s2mps11.o
......
...@@ -318,6 +318,7 @@ struct reg_init { ...@@ -318,6 +318,7 @@ struct reg_init {
}; };
struct bd718xx_regulator_data { struct bd718xx_regulator_data {
struct regulator_desc desc; struct regulator_desc desc;
const struct rohm_dvs_config dvs;
const struct reg_init init; const struct reg_init init;
const struct reg_init *additional_inits; const struct reg_init *additional_inits;
int additional_init_amnt; int additional_init_amnt;
...@@ -349,133 +350,15 @@ static const struct reg_init bd71837_ldo6_inits[] = { ...@@ -349,133 +350,15 @@ static const struct reg_init bd71837_ldo6_inits[] = {
}, },
}; };
#define NUM_DVS_BUCKS 4 static int buck_set_hw_dvs_levels(struct device_node *np,
struct of_dvs_setting {
const char *prop;
unsigned int reg;
};
static int set_dvs_levels(const struct of_dvs_setting *dvs,
struct device_node *np,
const struct regulator_desc *desc,
struct regmap *regmap)
{
int ret, i;
unsigned int uv;
ret = of_property_read_u32(np, dvs->prop, &uv);
if (ret) {
if (ret != -EINVAL)
return ret;
return 0;
}
for (i = 0; i < desc->n_voltages; i++) {
ret = regulator_desc_list_voltage_linear_range(desc, i);
if (ret < 0)
continue;
if (ret == uv) {
i <<= ffs(desc->vsel_mask) - 1;
ret = regmap_update_bits(regmap, dvs->reg,
DVS_BUCK_RUN_MASK, i);
break;
}
}
return ret;
}
static int buck4_set_hw_dvs_levels(struct device_node *np,
const struct regulator_desc *desc, const struct regulator_desc *desc,
struct regulator_config *cfg) struct regulator_config *cfg)
{ {
int ret, i; struct bd718xx_regulator_data *data;
const struct of_dvs_setting dvs[] = {
{
.prop = "rohm,dvs-run-voltage",
.reg = BD71837_REG_BUCK4_VOLT_RUN,
},
};
for (i = 0; i < ARRAY_SIZE(dvs); i++) { data = container_of(desc, struct bd718xx_regulator_data, desc);
ret = set_dvs_levels(&dvs[i], np, desc, cfg->regmap);
if (ret)
break;
}
return ret;
}
static int buck3_set_hw_dvs_levels(struct device_node *np,
const struct regulator_desc *desc,
struct regulator_config *cfg)
{
int ret, i;
const struct of_dvs_setting dvs[] = {
{
.prop = "rohm,dvs-run-voltage",
.reg = BD71837_REG_BUCK3_VOLT_RUN,
},
};
for (i = 0; i < ARRAY_SIZE(dvs); i++) { return rohm_regulator_set_dvs_levels(&data->dvs, np, desc, cfg->regmap);
ret = set_dvs_levels(&dvs[i], np, desc, cfg->regmap);
if (ret)
break;
}
return ret;
}
static int buck2_set_hw_dvs_levels(struct device_node *np,
const struct regulator_desc *desc,
struct regulator_config *cfg)
{
int ret, i;
const struct of_dvs_setting dvs[] = {
{
.prop = "rohm,dvs-run-voltage",
.reg = BD718XX_REG_BUCK2_VOLT_RUN,
},
{
.prop = "rohm,dvs-idle-voltage",
.reg = BD718XX_REG_BUCK2_VOLT_IDLE,
},
};
for (i = 0; i < ARRAY_SIZE(dvs); i++) {
ret = set_dvs_levels(&dvs[i], np, desc, cfg->regmap);
if (ret)
break;
}
return ret;
}
static int buck1_set_hw_dvs_levels(struct device_node *np,
const struct regulator_desc *desc,
struct regulator_config *cfg)
{
int ret, i;
const struct of_dvs_setting dvs[] = {
{
.prop = "rohm,dvs-run-voltage",
.reg = BD718XX_REG_BUCK1_VOLT_RUN,
},
{
.prop = "rohm,dvs-idle-voltage",
.reg = BD718XX_REG_BUCK1_VOLT_IDLE,
},
{
.prop = "rohm,dvs-suspend-voltage",
.reg = BD718XX_REG_BUCK1_VOLT_SUSP,
},
};
for (i = 0; i < ARRAY_SIZE(dvs); i++) {
ret = set_dvs_levels(&dvs[i], np, desc, cfg->regmap);
if (ret)
break;
}
return ret;
} }
static const struct bd718xx_regulator_data bd71847_regulators[] = { static const struct bd718xx_regulator_data bd71847_regulators[] = {
...@@ -496,7 +379,17 @@ static const struct bd718xx_regulator_data bd71847_regulators[] = { ...@@ -496,7 +379,17 @@ static const struct bd718xx_regulator_data bd71847_regulators[] = {
.enable_reg = BD718XX_REG_BUCK1_CTRL, .enable_reg = BD718XX_REG_BUCK1_CTRL,
.enable_mask = BD718XX_BUCK_EN, .enable_mask = BD718XX_BUCK_EN,
.owner = THIS_MODULE, .owner = THIS_MODULE,
.of_parse_cb = buck1_set_hw_dvs_levels, .of_parse_cb = buck_set_hw_dvs_levels,
},
.dvs = {
.level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE |
ROHM_DVS_LEVEL_SUSPEND,
.run_reg = BD718XX_REG_BUCK1_VOLT_RUN,
.run_mask = DVS_BUCK_RUN_MASK,
.idle_reg = BD718XX_REG_BUCK1_VOLT_IDLE,
.idle_mask = DVS_BUCK_RUN_MASK,
.suspend_reg = BD718XX_REG_BUCK1_VOLT_SUSP,
.suspend_mask = DVS_BUCK_RUN_MASK,
}, },
.init = { .init = {
.reg = BD718XX_REG_BUCK1_CTRL, .reg = BD718XX_REG_BUCK1_CTRL,
...@@ -520,7 +413,14 @@ static const struct bd718xx_regulator_data bd71847_regulators[] = { ...@@ -520,7 +413,14 @@ static const struct bd718xx_regulator_data bd71847_regulators[] = {
.enable_reg = BD718XX_REG_BUCK2_CTRL, .enable_reg = BD718XX_REG_BUCK2_CTRL,
.enable_mask = BD718XX_BUCK_EN, .enable_mask = BD718XX_BUCK_EN,
.owner = THIS_MODULE, .owner = THIS_MODULE,
.of_parse_cb = buck2_set_hw_dvs_levels, .of_parse_cb = buck_set_hw_dvs_levels,
},
.dvs = {
.level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE,
.run_reg = BD718XX_REG_BUCK2_VOLT_RUN,
.run_mask = DVS_BUCK_RUN_MASK,
.idle_reg = BD718XX_REG_BUCK2_VOLT_IDLE,
.idle_mask = DVS_BUCK_RUN_MASK,
}, },
.init = { .init = {
.reg = BD718XX_REG_BUCK2_CTRL, .reg = BD718XX_REG_BUCK2_CTRL,
...@@ -792,7 +692,17 @@ static const struct bd718xx_regulator_data bd71837_regulators[] = { ...@@ -792,7 +692,17 @@ static const struct bd718xx_regulator_data bd71837_regulators[] = {
.enable_reg = BD718XX_REG_BUCK1_CTRL, .enable_reg = BD718XX_REG_BUCK1_CTRL,
.enable_mask = BD718XX_BUCK_EN, .enable_mask = BD718XX_BUCK_EN,
.owner = THIS_MODULE, .owner = THIS_MODULE,
.of_parse_cb = buck1_set_hw_dvs_levels, .of_parse_cb = buck_set_hw_dvs_levels,
},
.dvs = {
.level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE |
ROHM_DVS_LEVEL_SUSPEND,
.run_reg = BD718XX_REG_BUCK1_VOLT_RUN,
.run_mask = DVS_BUCK_RUN_MASK,
.idle_reg = BD718XX_REG_BUCK1_VOLT_IDLE,
.idle_mask = DVS_BUCK_RUN_MASK,
.suspend_reg = BD718XX_REG_BUCK1_VOLT_SUSP,
.suspend_mask = DVS_BUCK_RUN_MASK,
}, },
.init = { .init = {
.reg = BD718XX_REG_BUCK1_CTRL, .reg = BD718XX_REG_BUCK1_CTRL,
...@@ -816,7 +726,14 @@ static const struct bd718xx_regulator_data bd71837_regulators[] = { ...@@ -816,7 +726,14 @@ static const struct bd718xx_regulator_data bd71837_regulators[] = {
.enable_reg = BD718XX_REG_BUCK2_CTRL, .enable_reg = BD718XX_REG_BUCK2_CTRL,
.enable_mask = BD718XX_BUCK_EN, .enable_mask = BD718XX_BUCK_EN,
.owner = THIS_MODULE, .owner = THIS_MODULE,
.of_parse_cb = buck2_set_hw_dvs_levels, .of_parse_cb = buck_set_hw_dvs_levels,
},
.dvs = {
.level_map = ROHM_DVS_LEVEL_RUN | ROHM_DVS_LEVEL_IDLE,
.run_reg = BD718XX_REG_BUCK2_VOLT_RUN,
.run_mask = DVS_BUCK_RUN_MASK,
.idle_reg = BD718XX_REG_BUCK2_VOLT_IDLE,
.idle_mask = DVS_BUCK_RUN_MASK,
}, },
.init = { .init = {
.reg = BD718XX_REG_BUCK2_CTRL, .reg = BD718XX_REG_BUCK2_CTRL,
...@@ -840,7 +757,12 @@ static const struct bd718xx_regulator_data bd71837_regulators[] = { ...@@ -840,7 +757,12 @@ static const struct bd718xx_regulator_data bd71837_regulators[] = {
.enable_reg = BD71837_REG_BUCK3_CTRL, .enable_reg = BD71837_REG_BUCK3_CTRL,
.enable_mask = BD718XX_BUCK_EN, .enable_mask = BD718XX_BUCK_EN,
.owner = THIS_MODULE, .owner = THIS_MODULE,
.of_parse_cb = buck3_set_hw_dvs_levels, .of_parse_cb = buck_set_hw_dvs_levels,
},
.dvs = {
.level_map = ROHM_DVS_LEVEL_RUN,
.run_reg = BD71837_REG_BUCK3_VOLT_RUN,
.run_mask = DVS_BUCK_RUN_MASK,
}, },
.init = { .init = {
.reg = BD71837_REG_BUCK3_CTRL, .reg = BD71837_REG_BUCK3_CTRL,
...@@ -864,7 +786,12 @@ static const struct bd718xx_regulator_data bd71837_regulators[] = { ...@@ -864,7 +786,12 @@ static const struct bd718xx_regulator_data bd71837_regulators[] = {
.enable_reg = BD71837_REG_BUCK4_CTRL, .enable_reg = BD71837_REG_BUCK4_CTRL,
.enable_mask = BD718XX_BUCK_EN, .enable_mask = BD718XX_BUCK_EN,
.owner = THIS_MODULE, .owner = THIS_MODULE,
.of_parse_cb = buck4_set_hw_dvs_levels, .of_parse_cb = buck_set_hw_dvs_levels,
},
.dvs = {
.level_map = ROHM_DVS_LEVEL_RUN,
.run_reg = BD71837_REG_BUCK4_VOLT_RUN,
.run_mask = DVS_BUCK_RUN_MASK,
}, },
.init = { .init = {
.reg = BD71837_REG_BUCK4_CTRL, .reg = BD71837_REG_BUCK4_CTRL,
...@@ -1150,6 +1077,7 @@ static int bd718xx_probe(struct platform_device *pdev) ...@@ -1150,6 +1077,7 @@ static int bd718xx_probe(struct platform_device *pdev)
bool use_snvs; bool use_snvs;
const struct bd718xx_regulator_data *reg_data; const struct bd718xx_regulator_data *reg_data;
unsigned int num_reg_data; unsigned int num_reg_data;
enum rohm_chip_type chip = platform_get_device_id(pdev)->driver_data;
mfd = dev_get_drvdata(pdev->dev.parent); mfd = dev_get_drvdata(pdev->dev.parent);
if (!mfd) { if (!mfd) {
...@@ -1158,7 +1086,7 @@ static int bd718xx_probe(struct platform_device *pdev) ...@@ -1158,7 +1086,7 @@ static int bd718xx_probe(struct platform_device *pdev)
goto err; goto err;
} }
switch (mfd->chip.chip_type) { switch (chip) {
case ROHM_CHIP_TYPE_BD71837: case ROHM_CHIP_TYPE_BD71837:
reg_data = bd71837_regulators; reg_data = bd71837_regulators;
num_reg_data = ARRAY_SIZE(bd71837_regulators); num_reg_data = ARRAY_SIZE(bd71837_regulators);
...@@ -1275,11 +1203,19 @@ static int bd718xx_probe(struct platform_device *pdev) ...@@ -1275,11 +1203,19 @@ static int bd718xx_probe(struct platform_device *pdev)
return err; return err;
} }
static const struct platform_device_id bd718x7_pmic_id[] = {
{ "bd71837-pmic", ROHM_CHIP_TYPE_BD71837 },
{ "bd71847-pmic", ROHM_CHIP_TYPE_BD71847 },
{ },
};
MODULE_DEVICE_TABLE(platform, bd718x7_pmic_id);
static struct platform_driver bd718xx_regulator = { static struct platform_driver bd718xx_regulator = {
.driver = { .driver = {
.name = "bd718xx-pmic", .name = "bd718xx-pmic",
}, },
.probe = bd718xx_probe, .probe = bd718xx_probe,
.id_table = bd718x7_pmic_id,
}; };
module_platform_driver(bd718xx_regulator); module_platform_driver(bd718xx_regulator);
......
// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2020 ROHM Semiconductors
#include <linux/errno.h>
#include <linux/mfd/rohm-generic.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/regmap.h>
#include <linux/regulator/driver.h>
static int set_dvs_level(const struct regulator_desc *desc,
struct device_node *np, struct regmap *regmap,
char *prop, unsigned int reg, unsigned int mask,
unsigned int omask, unsigned int oreg)
{
int ret, i;
uint32_t uv;
ret = of_property_read_u32(np, prop, &uv);
if (ret) {
if (ret != -EINVAL)
return ret;
return 0;
}
if (uv == 0) {
if (omask)
return regmap_update_bits(regmap, oreg, omask, 0);
}
for (i = 0; i < desc->n_voltages; i++) {
ret = regulator_desc_list_voltage_linear_range(desc, i);
if (ret < 0)
continue;
if (ret == uv) {
i <<= ffs(desc->vsel_mask) - 1;
ret = regmap_update_bits(regmap, reg, mask, i);
if (omask && !ret)
ret = regmap_update_bits(regmap, oreg, omask,
omask);
break;
}
}
return ret;
}
int rohm_regulator_set_dvs_levels(const struct rohm_dvs_config *dvs,
struct device_node *np,
const struct regulator_desc *desc,
struct regmap *regmap)
{
int i, ret = 0;
char *prop;
unsigned int reg, mask, omask, oreg = desc->enable_reg;
for (i = 0; i < ROHM_DVS_LEVEL_MAX && !ret; i++) {
if (dvs->level_map & (1 << i)) {
switch (i + 1) {
case ROHM_DVS_LEVEL_RUN:
prop = "rohm,dvs-run-voltage";
reg = dvs->run_reg;
mask = dvs->run_mask;
omask = dvs->run_on_mask;
break;
case ROHM_DVS_LEVEL_IDLE:
prop = "rohm,dvs-idle-voltage";
reg = dvs->idle_reg;
mask = dvs->idle_mask;
omask = dvs->idle_on_mask;
break;
case ROHM_DVS_LEVEL_SUSPEND:
prop = "rohm,dvs-suspend-voltage";
reg = dvs->suspend_reg;
mask = dvs->suspend_mask;
omask = dvs->suspend_on_mask;
break;
case ROHM_DVS_LEVEL_LPSR:
prop = "rohm,dvs-lpsr-voltage";
reg = dvs->lpsr_reg;
mask = dvs->lpsr_mask;
omask = dvs->lpsr_on_mask;
break;
default:
return -EINVAL;
}
ret = set_dvs_level(desc, np, regmap, prop, reg, mask,
omask, oreg);
}
}
return ret;
}
EXPORT_SYMBOL(rohm_regulator_set_dvs_levels);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
MODULE_DESCRIPTION("Generic helpers for ROHM PMIC regulator drivers");
...@@ -498,12 +498,13 @@ config RTC_DRV_M41T80_WDT ...@@ -498,12 +498,13 @@ config RTC_DRV_M41T80_WDT
help help
If you say Y here you will get support for the If you say Y here you will get support for the
watchdog timer in the ST M41T60 and M41T80 RTC chips series. watchdog timer in the ST M41T60 and M41T80 RTC chips series.
config RTC_DRV_BD70528 config RTC_DRV_BD70528
tristate "ROHM BD70528 PMIC RTC" tristate "ROHM BD70528 PMIC RTC"
depends on MFD_ROHM_BD70528 && (BD70528_WATCHDOG || !BD70528_WATCHDOG) depends on MFD_ROHM_BD70528 && (BD70528_WATCHDOG || !BD70528_WATCHDOG)
help help
If you say Y here you will get support for the RTC If you say Y here you will get support for the RTC
on ROHM BD70528 Power Management IC. block on ROHM BD70528 and BD71828 Power Management IC.
This driver can also be built as a module. If so, the module This driver can also be built as a module. If so, the module
will be called rtc-bd70528. will be called rtc-bd70528.
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include <linux/bcd.h> #include <linux/bcd.h>
#include <linux/mfd/rohm-bd70528.h> #include <linux/mfd/rohm-bd70528.h>
#include <linux/mfd/rohm-bd71828.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
...@@ -15,7 +16,7 @@ ...@@ -15,7 +16,7 @@
/* /*
* We read regs RTC_SEC => RTC_YEAR * We read regs RTC_SEC => RTC_YEAR
* this struct is ordered according to chip registers. * this struct is ordered according to chip registers.
* Keep it u8 only to avoid padding issues. * Keep it u8 only (or packed) to avoid padding issues.
*/ */
struct bd70528_rtc_day { struct bd70528_rtc_day {
u8 sec; u8 sec;
...@@ -36,6 +37,13 @@ struct bd70528_rtc_wake { ...@@ -36,6 +37,13 @@ struct bd70528_rtc_wake {
u8 ctrl; u8 ctrl;
} __packed; } __packed;
struct bd71828_rtc_alm {
struct bd70528_rtc_data alm0;
struct bd70528_rtc_data alm1;
u8 alm_mask;
u8 alm1_mask;
} __packed;
struct bd70528_rtc_alm { struct bd70528_rtc_alm {
struct bd70528_rtc_data data; struct bd70528_rtc_data data;
u8 alm_mask; u8 alm_mask;
...@@ -43,8 +51,10 @@ struct bd70528_rtc_alm { ...@@ -43,8 +51,10 @@ struct bd70528_rtc_alm {
} __packed; } __packed;
struct bd70528_rtc { struct bd70528_rtc {
struct rohm_regmap_dev *mfd; struct rohm_regmap_dev *parent;
struct device *dev; struct device *dev;
u8 reg_time_start;
bool has_rtc_timers;
}; };
static int bd70528_set_wake(struct rohm_regmap_dev *bd70528, static int bd70528_set_wake(struct rohm_regmap_dev *bd70528,
...@@ -123,14 +133,14 @@ static int bd70528_set_rtc_based_timers(struct bd70528_rtc *r, int new_state, ...@@ -123,14 +133,14 @@ static int bd70528_set_rtc_based_timers(struct bd70528_rtc *r, int new_state,
{ {
int ret; int ret;
ret = bd70528_wdt_set(r->mfd, new_state & BD70528_WDT_STATE_BIT, ret = bd70528_wdt_set(r->parent, new_state & BD70528_WDT_STATE_BIT,
old_state); old_state);
if (ret) { if (ret) {
dev_err(r->dev, dev_err(r->dev,
"Failed to disable WDG for RTC setting (%d)\n", ret); "Failed to disable WDG for RTC setting (%d)\n", ret);
return ret; return ret;
} }
ret = bd70528_set_elapsed_tmr(r->mfd, ret = bd70528_set_elapsed_tmr(r->parent,
new_state & BD70528_ELAPSED_STATE_BIT, new_state & BD70528_ELAPSED_STATE_BIT,
old_state); old_state);
if (ret) { if (ret) {
...@@ -138,7 +148,7 @@ static int bd70528_set_rtc_based_timers(struct bd70528_rtc *r, int new_state, ...@@ -138,7 +148,7 @@ static int bd70528_set_rtc_based_timers(struct bd70528_rtc *r, int new_state,
"Failed to disable 'elapsed timer' for RTC setting\n"); "Failed to disable 'elapsed timer' for RTC setting\n");
return ret; return ret;
} }
ret = bd70528_set_wake(r->mfd, new_state & BD70528_WAKE_STATE_BIT, ret = bd70528_set_wake(r->parent, new_state & BD70528_WAKE_STATE_BIT,
old_state); old_state);
if (ret) { if (ret) {
dev_err(r->dev, dev_err(r->dev,
...@@ -152,12 +162,18 @@ static int bd70528_set_rtc_based_timers(struct bd70528_rtc *r, int new_state, ...@@ -152,12 +162,18 @@ static int bd70528_set_rtc_based_timers(struct bd70528_rtc *r, int new_state,
static int bd70528_re_enable_rtc_based_timers(struct bd70528_rtc *r, static int bd70528_re_enable_rtc_based_timers(struct bd70528_rtc *r,
int old_state) int old_state)
{ {
if (!r->has_rtc_timers)
return 0;
return bd70528_set_rtc_based_timers(r, old_state, NULL); return bd70528_set_rtc_based_timers(r, old_state, NULL);
} }
static int bd70528_disable_rtc_based_timers(struct bd70528_rtc *r, static int bd70528_disable_rtc_based_timers(struct bd70528_rtc *r,
int *old_state) int *old_state)
{ {
if (!r->has_rtc_timers)
return 0;
return bd70528_set_rtc_based_timers(r, 0, old_state); return bd70528_set_rtc_based_timers(r, 0, old_state);
} }
...@@ -213,22 +229,52 @@ static inline void rtc2tm(struct bd70528_rtc_data *r, struct rtc_time *t) ...@@ -213,22 +229,52 @@ static inline void rtc2tm(struct bd70528_rtc_data *r, struct rtc_time *t)
t->tm_wday = bcd2bin(r->week & BD70528_MASK_RTC_WEEK); t->tm_wday = bcd2bin(r->week & BD70528_MASK_RTC_WEEK);
} }
static int bd71828_set_alarm(struct device *dev, struct rtc_wkalrm *a)
{
int ret;
struct bd71828_rtc_alm alm;
struct bd70528_rtc *r = dev_get_drvdata(dev);
struct rohm_regmap_dev *parent = r->parent;
ret = regmap_bulk_read(parent->regmap, BD71828_REG_RTC_ALM_START,
&alm, sizeof(alm));
if (ret) {
dev_err(dev, "Failed to read alarm regs\n");
return ret;
}
tm2rtc(&a->time, &alm.alm0);
if (!a->enabled)
alm.alm_mask &= ~BD70528_MASK_ALM_EN;
else
alm.alm_mask |= BD70528_MASK_ALM_EN;
ret = regmap_bulk_write(parent->regmap, BD71828_REG_RTC_ALM_START,
&alm, sizeof(alm));
if (ret)
dev_err(dev, "Failed to set alarm time\n");
return ret;
}
static int bd70528_set_alarm(struct device *dev, struct rtc_wkalrm *a) static int bd70528_set_alarm(struct device *dev, struct rtc_wkalrm *a)
{ {
struct bd70528_rtc_wake wake; struct bd70528_rtc_wake wake;
struct bd70528_rtc_alm alm; struct bd70528_rtc_alm alm;
int ret; int ret;
struct bd70528_rtc *r = dev_get_drvdata(dev); struct bd70528_rtc *r = dev_get_drvdata(dev);
struct rohm_regmap_dev *bd70528 = r->mfd; struct rohm_regmap_dev *parent = r->parent;
ret = regmap_bulk_read(bd70528->regmap, BD70528_REG_RTC_WAKE_START, ret = regmap_bulk_read(parent->regmap, BD70528_REG_RTC_WAKE_START,
&wake, sizeof(wake)); &wake, sizeof(wake));
if (ret) { if (ret) {
dev_err(dev, "Failed to read wake regs\n"); dev_err(dev, "Failed to read wake regs\n");
return ret; return ret;
} }
ret = regmap_bulk_read(bd70528->regmap, BD70528_REG_RTC_ALM_START, ret = regmap_bulk_read(parent->regmap, BD70528_REG_RTC_ALM_START,
&alm, sizeof(alm)); &alm, sizeof(alm));
if (ret) { if (ret) {
dev_err(dev, "Failed to read alarm regs\n"); dev_err(dev, "Failed to read alarm regs\n");
...@@ -246,14 +292,14 @@ static int bd70528_set_alarm(struct device *dev, struct rtc_wkalrm *a) ...@@ -246,14 +292,14 @@ static int bd70528_set_alarm(struct device *dev, struct rtc_wkalrm *a)
wake.ctrl &= ~BD70528_MASK_WAKE_EN; wake.ctrl &= ~BD70528_MASK_WAKE_EN;
} }
ret = regmap_bulk_write(bd70528->regmap, ret = regmap_bulk_write(parent->regmap,
BD70528_REG_RTC_WAKE_START, &wake, BD70528_REG_RTC_WAKE_START, &wake,
sizeof(wake)); sizeof(wake));
if (ret) { if (ret) {
dev_err(dev, "Failed to set wake time\n"); dev_err(dev, "Failed to set wake time\n");
return ret; return ret;
} }
ret = regmap_bulk_write(bd70528->regmap, BD70528_REG_RTC_ALM_START, ret = regmap_bulk_write(parent->regmap, BD70528_REG_RTC_ALM_START,
&alm, sizeof(alm)); &alm, sizeof(alm));
if (ret) if (ret)
dev_err(dev, "Failed to set alarm time\n"); dev_err(dev, "Failed to set alarm time\n");
...@@ -261,14 +307,38 @@ static int bd70528_set_alarm(struct device *dev, struct rtc_wkalrm *a) ...@@ -261,14 +307,38 @@ static int bd70528_set_alarm(struct device *dev, struct rtc_wkalrm *a)
return ret; return ret;
} }
static int bd71828_read_alarm(struct device *dev, struct rtc_wkalrm *a)
{
int ret;
struct bd71828_rtc_alm alm;
struct bd70528_rtc *r = dev_get_drvdata(dev);
struct rohm_regmap_dev *parent = r->parent;
ret = regmap_bulk_read(parent->regmap, BD71828_REG_RTC_ALM_START,
&alm, sizeof(alm));
if (ret) {
dev_err(dev, "Failed to read alarm regs\n");
return ret;
}
rtc2tm(&alm.alm0, &a->time);
a->time.tm_mday = -1;
a->time.tm_mon = -1;
a->time.tm_year = -1;
a->enabled = !!(alm.alm_mask & BD70528_MASK_ALM_EN);
a->pending = 0;
return 0;
}
static int bd70528_read_alarm(struct device *dev, struct rtc_wkalrm *a) static int bd70528_read_alarm(struct device *dev, struct rtc_wkalrm *a)
{ {
struct bd70528_rtc_alm alm; struct bd70528_rtc_alm alm;
int ret; int ret;
struct bd70528_rtc *r = dev_get_drvdata(dev); struct bd70528_rtc *r = dev_get_drvdata(dev);
struct rohm_regmap_dev *bd70528 = r->mfd; struct rohm_regmap_dev *parent = r->parent;
ret = regmap_bulk_read(bd70528->regmap, BD70528_REG_RTC_ALM_START, ret = regmap_bulk_read(parent->regmap, BD70528_REG_RTC_ALM_START,
&alm, sizeof(alm)); &alm, sizeof(alm));
if (ret) { if (ret) {
dev_err(dev, "Failed to read alarm regs\n"); dev_err(dev, "Failed to read alarm regs\n");
...@@ -290,14 +360,14 @@ static int bd70528_set_time_locked(struct device *dev, struct rtc_time *t) ...@@ -290,14 +360,14 @@ static int bd70528_set_time_locked(struct device *dev, struct rtc_time *t)
int ret, tmpret, old_states; int ret, tmpret, old_states;
struct bd70528_rtc_data rtc_data; struct bd70528_rtc_data rtc_data;
struct bd70528_rtc *r = dev_get_drvdata(dev); struct bd70528_rtc *r = dev_get_drvdata(dev);
struct rohm_regmap_dev *bd70528 = r->mfd; struct rohm_regmap_dev *parent = r->parent;
ret = bd70528_disable_rtc_based_timers(r, &old_states); ret = bd70528_disable_rtc_based_timers(r, &old_states);
if (ret) if (ret)
return ret; return ret;
tmpret = regmap_bulk_read(bd70528->regmap, tmpret = regmap_bulk_read(parent->regmap,
BD70528_REG_RTC_START, &rtc_data, r->reg_time_start, &rtc_data,
sizeof(rtc_data)); sizeof(rtc_data));
if (tmpret) { if (tmpret) {
dev_err(dev, "Failed to read RTC time registers\n"); dev_err(dev, "Failed to read RTC time registers\n");
...@@ -305,8 +375,8 @@ static int bd70528_set_time_locked(struct device *dev, struct rtc_time *t) ...@@ -305,8 +375,8 @@ static int bd70528_set_time_locked(struct device *dev, struct rtc_time *t)
} }
tm2rtc(t, &rtc_data); tm2rtc(t, &rtc_data);
tmpret = regmap_bulk_write(bd70528->regmap, tmpret = regmap_bulk_write(parent->regmap,
BD70528_REG_RTC_START, &rtc_data, r->reg_time_start, &rtc_data,
sizeof(rtc_data)); sizeof(rtc_data));
if (tmpret) { if (tmpret) {
dev_err(dev, "Failed to set RTC time\n"); dev_err(dev, "Failed to set RTC time\n");
...@@ -321,27 +391,32 @@ static int bd70528_set_time_locked(struct device *dev, struct rtc_time *t) ...@@ -321,27 +391,32 @@ static int bd70528_set_time_locked(struct device *dev, struct rtc_time *t)
return ret; return ret;
} }
static int bd71828_set_time(struct device *dev, struct rtc_time *t)
{
return bd70528_set_time_locked(dev, t);
}
static int bd70528_set_time(struct device *dev, struct rtc_time *t) static int bd70528_set_time(struct device *dev, struct rtc_time *t)
{ {
int ret; int ret;
struct bd70528_rtc *r = dev_get_drvdata(dev); struct bd70528_rtc *r = dev_get_drvdata(dev);
bd70528_wdt_lock(r->mfd); bd70528_wdt_lock(r->parent);
ret = bd70528_set_time_locked(dev, t); ret = bd70528_set_time_locked(dev, t);
bd70528_wdt_unlock(r->mfd); bd70528_wdt_unlock(r->parent);
return ret; return ret;
} }
static int bd70528_get_time(struct device *dev, struct rtc_time *t) static int bd70528_get_time(struct device *dev, struct rtc_time *t)
{ {
struct bd70528_rtc *r = dev_get_drvdata(dev); struct bd70528_rtc *r = dev_get_drvdata(dev);
struct rohm_regmap_dev *bd70528 = r->mfd; struct rohm_regmap_dev *parent = r->parent;
struct bd70528_rtc_data rtc_data; struct bd70528_rtc_data rtc_data;
int ret; int ret;
/* read the RTC date and time registers all at once */ /* read the RTC date and time registers all at once */
ret = regmap_bulk_read(bd70528->regmap, ret = regmap_bulk_read(parent->regmap,
BD70528_REG_RTC_START, &rtc_data, r->reg_time_start, &rtc_data,
sizeof(rtc_data)); sizeof(rtc_data));
if (ret) { if (ret) {
dev_err(dev, "Failed to read RTC time (err %d)\n", ret); dev_err(dev, "Failed to read RTC time (err %d)\n", ret);
...@@ -362,19 +437,36 @@ static int bd70528_alm_enable(struct device *dev, unsigned int enabled) ...@@ -362,19 +437,36 @@ static int bd70528_alm_enable(struct device *dev, unsigned int enabled)
if (enabled) if (enabled)
enableval = 0; enableval = 0;
bd70528_wdt_lock(r->mfd); bd70528_wdt_lock(r->parent);
ret = bd70528_set_wake(r->mfd, enabled, NULL); ret = bd70528_set_wake(r->parent, enabled, NULL);
if (ret) { if (ret) {
dev_err(dev, "Failed to change wake state\n"); dev_err(dev, "Failed to change wake state\n");
goto out_unlock; goto out_unlock;
} }
ret = regmap_update_bits(r->mfd->regmap, BD70528_REG_RTC_ALM_MASK, ret = regmap_update_bits(r->parent->regmap, BD70528_REG_RTC_ALM_MASK,
BD70528_MASK_ALM_EN, enableval); BD70528_MASK_ALM_EN, enableval);
if (ret) if (ret)
dev_err(dev, "Failed to change alarm state\n"); dev_err(dev, "Failed to change alarm state\n");
out_unlock: out_unlock:
bd70528_wdt_unlock(r->mfd); bd70528_wdt_unlock(r->parent);
return ret;
}
static int bd71828_alm_enable(struct device *dev, unsigned int enabled)
{
int ret;
struct bd70528_rtc *r = dev_get_drvdata(dev);
unsigned int enableval = BD70528_MASK_ALM_EN;
if (!enabled)
enableval = 0;
ret = regmap_update_bits(r->parent->regmap, BD71828_REG_RTC_ALM0_MASK,
BD70528_MASK_ALM_EN, enableval);
if (ret)
dev_err(dev, "Failed to change alarm state\n");
return ret; return ret;
} }
...@@ -386,6 +478,14 @@ static const struct rtc_class_ops bd70528_rtc_ops = { ...@@ -386,6 +478,14 @@ static const struct rtc_class_ops bd70528_rtc_ops = {
.alarm_irq_enable = bd70528_alm_enable, .alarm_irq_enable = bd70528_alm_enable,
}; };
static const struct rtc_class_ops bd71828_rtc_ops = {
.read_time = bd70528_get_time,
.set_time = bd71828_set_time,
.read_alarm = bd71828_read_alarm,
.set_alarm = bd71828_set_alarm,
.alarm_irq_enable = bd71828_alm_enable,
};
static irqreturn_t alm_hndlr(int irq, void *data) static irqreturn_t alm_hndlr(int irq, void *data)
{ {
struct rtc_device *rtc = data; struct rtc_device *rtc = data;
...@@ -397,14 +497,19 @@ static irqreturn_t alm_hndlr(int irq, void *data) ...@@ -397,14 +497,19 @@ static irqreturn_t alm_hndlr(int irq, void *data)
static int bd70528_probe(struct platform_device *pdev) static int bd70528_probe(struct platform_device *pdev)
{ {
struct bd70528_rtc *bd_rtc; struct bd70528_rtc *bd_rtc;
struct rohm_regmap_dev *mfd; const struct rtc_class_ops *rtc_ops;
struct rohm_regmap_dev *parent;
const char *irq_name;
int ret; int ret;
struct rtc_device *rtc; struct rtc_device *rtc;
int irq; int irq;
unsigned int hr; unsigned int hr;
bool enable_main_irq = false;
u8 hour_reg;
enum rohm_chip_type chip = platform_get_device_id(pdev)->driver_data;
mfd = dev_get_drvdata(pdev->dev.parent); parent = dev_get_drvdata(pdev->dev.parent);
if (!mfd) { if (!parent) {
dev_err(&pdev->dev, "No MFD driver data\n"); dev_err(&pdev->dev, "No MFD driver data\n");
return -EINVAL; return -EINVAL;
} }
...@@ -412,16 +517,39 @@ static int bd70528_probe(struct platform_device *pdev) ...@@ -412,16 +517,39 @@ static int bd70528_probe(struct platform_device *pdev)
if (!bd_rtc) if (!bd_rtc)
return -ENOMEM; return -ENOMEM;
bd_rtc->mfd = mfd; bd_rtc->parent = parent;
bd_rtc->dev = &pdev->dev; bd_rtc->dev = &pdev->dev;
irq = platform_get_irq_byname(pdev, "bd70528-rtc-alm"); switch (chip) {
if (irq < 0) case ROHM_CHIP_TYPE_BD70528:
irq_name = "bd70528-rtc-alm";
bd_rtc->has_rtc_timers = true;
bd_rtc->reg_time_start = BD70528_REG_RTC_START;
hour_reg = BD70528_REG_RTC_HOUR;
enable_main_irq = true;
rtc_ops = &bd70528_rtc_ops;
break;
case ROHM_CHIP_TYPE_BD71828:
irq_name = "bd71828-rtc-alm-0";
bd_rtc->reg_time_start = BD71828_REG_RTC_START;
hour_reg = BD71828_REG_RTC_HOUR;
rtc_ops = &bd71828_rtc_ops;
break;
default:
dev_err(&pdev->dev, "Unknown chip\n");
return -ENOENT;
}
irq = platform_get_irq_byname(pdev, irq_name);
if (irq < 0) {
dev_err(&pdev->dev, "Failed to get irq\n");
return irq; return irq;
}
platform_set_drvdata(pdev, bd_rtc); platform_set_drvdata(pdev, bd_rtc);
ret = regmap_read(mfd->regmap, BD70528_REG_RTC_HOUR, &hr); ret = regmap_read(parent->regmap, hour_reg, &hr);
if (ret) { if (ret) {
dev_err(&pdev->dev, "Failed to reag RTC clock\n"); dev_err(&pdev->dev, "Failed to reag RTC clock\n");
...@@ -431,10 +559,10 @@ static int bd70528_probe(struct platform_device *pdev) ...@@ -431,10 +559,10 @@ static int bd70528_probe(struct platform_device *pdev)
if (!(hr & BD70528_MASK_RTC_HOUR_24H)) { if (!(hr & BD70528_MASK_RTC_HOUR_24H)) {
struct rtc_time t; struct rtc_time t;
ret = bd70528_get_time(&pdev->dev, &t); ret = rtc_ops->read_time(&pdev->dev, &t);
if (!ret) if (!ret)
ret = bd70528_set_time(&pdev->dev, &t); ret = rtc_ops->set_time(&pdev->dev, &t);
if (ret) { if (ret) {
dev_err(&pdev->dev, dev_err(&pdev->dev,
...@@ -454,7 +582,7 @@ static int bd70528_probe(struct platform_device *pdev) ...@@ -454,7 +582,7 @@ static int bd70528_probe(struct platform_device *pdev)
rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
rtc->range_max = RTC_TIMESTAMP_END_2099; rtc->range_max = RTC_TIMESTAMP_END_2099;
rtc->ops = &bd70528_rtc_ops; rtc->ops = rtc_ops;
/* Request alarm IRQ prior to registerig the RTC */ /* Request alarm IRQ prior to registerig the RTC */
ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, &alm_hndlr, ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, &alm_hndlr,
...@@ -468,27 +596,37 @@ static int bd70528_probe(struct platform_device *pdev) ...@@ -468,27 +596,37 @@ static int bd70528_probe(struct platform_device *pdev)
* leave them enabled as irq-controller should disable irqs * leave them enabled as irq-controller should disable irqs
* from sub-registers when IRQ is disabled or freed. * from sub-registers when IRQ is disabled or freed.
*/ */
ret = regmap_update_bits(mfd->regmap, if (enable_main_irq) {
ret = regmap_update_bits(parent->regmap,
BD70528_REG_INT_MAIN_MASK, BD70528_REG_INT_MAIN_MASK,
BD70528_INT_RTC_MASK, 0); BD70528_INT_RTC_MASK, 0);
if (ret) { if (ret) {
dev_err(&pdev->dev, "Failed to enable RTC interrupts\n"); dev_err(&pdev->dev, "Failed to enable RTC interrupts\n");
return ret; return ret;
}
} }
return rtc_register_device(rtc); return rtc_register_device(rtc);
} }
static const struct platform_device_id bd718x7_rtc_id[] = {
{ "bd70528-rtc", ROHM_CHIP_TYPE_BD70528 },
{ "bd71828-rtc", ROHM_CHIP_TYPE_BD71828 },
{ },
};
MODULE_DEVICE_TABLE(platform, bd718x7_rtc_id);
static struct platform_driver bd70528_rtc = { static struct platform_driver bd70528_rtc = {
.driver = { .driver = {
.name = "bd70528-rtc" .name = "bd70528-rtc"
}, },
.probe = bd70528_probe, .probe = bd70528_probe,
.id_table = bd718x7_rtc_id,
}; };
module_platform_driver(bd70528_rtc); module_platform_driver(bd70528_rtc);
MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>"); MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
MODULE_DESCRIPTION("BD70528 RTC driver"); MODULE_DESCRIPTION("ROHM BD70528 and BD71828 PMIC RTC driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:bd70528-rtc"); MODULE_ALIAS("platform:bd70528-rtc");
...@@ -525,9 +525,6 @@ u8 db8500_prcmu_get_power_state_result(void); ...@@ -525,9 +525,6 @@ u8 db8500_prcmu_get_power_state_result(void);
void db8500_prcmu_enable_wakeups(u32 wakeups); void db8500_prcmu_enable_wakeups(u32 wakeups);
int db8500_prcmu_set_epod(u16 epod_id, u8 epod_state); int db8500_prcmu_set_epod(u16 epod_id, u8 epod_state);
int db8500_prcmu_request_clock(u8 clock, bool enable); int db8500_prcmu_request_clock(u8 clock, bool enable);
int db8500_prcmu_set_display_clocks(void);
int db8500_prcmu_disable_dsipll(void);
int db8500_prcmu_enable_dsipll(void);
void db8500_prcmu_config_abb_event_readout(u32 abb_events); void db8500_prcmu_config_abb_event_readout(u32 abb_events);
void db8500_prcmu_get_abb_event_buffer(void __iomem **buf); void db8500_prcmu_get_abb_event_buffer(void __iomem **buf);
int db8500_prcmu_config_esram0_deep_sleep(u8 state); int db8500_prcmu_config_esram0_deep_sleep(u8 state);
...@@ -682,21 +679,6 @@ static inline int db8500_prcmu_request_clock(u8 clock, bool enable) ...@@ -682,21 +679,6 @@ static inline int db8500_prcmu_request_clock(u8 clock, bool enable)
return 0; return 0;
} }
static inline int db8500_prcmu_set_display_clocks(void)
{
return 0;
}
static inline int db8500_prcmu_disable_dsipll(void)
{
return 0;
}
static inline int db8500_prcmu_enable_dsipll(void)
{
return 0;
}
static inline int db8500_prcmu_config_esram0_deep_sleep(u8 state) static inline int db8500_prcmu_config_esram0_deep_sleep(u8 state)
{ {
return 0; return 0;
......
...@@ -321,21 +321,6 @@ static inline bool prcmu_is_ac_wake_requested(void) ...@@ -321,21 +321,6 @@ static inline bool prcmu_is_ac_wake_requested(void)
return db8500_prcmu_is_ac_wake_requested(); return db8500_prcmu_is_ac_wake_requested();
} }
static inline int prcmu_set_display_clocks(void)
{
return db8500_prcmu_set_display_clocks();
}
static inline int prcmu_disable_dsipll(void)
{
return db8500_prcmu_disable_dsipll();
}
static inline int prcmu_enable_dsipll(void)
{
return db8500_prcmu_enable_dsipll();
}
static inline int prcmu_config_esram0_deep_sleep(u8 state) static inline int prcmu_config_esram0_deep_sleep(u8 state)
{ {
return db8500_prcmu_config_esram0_deep_sleep(state); return db8500_prcmu_config_esram0_deep_sleep(state);
...@@ -511,21 +496,6 @@ static inline bool prcmu_is_ac_wake_requested(void) ...@@ -511,21 +496,6 @@ static inline bool prcmu_is_ac_wake_requested(void)
return false; return false;
} }
static inline int prcmu_set_display_clocks(void)
{
return 0;
}
static inline int prcmu_disable_dsipll(void)
{
return 0;
}
static inline int prcmu_enable_dsipll(void)
{
return 0;
}
static inline int prcmu_config_esram0_deep_sleep(u8 state) static inline int prcmu_config_esram0_deep_sleep(u8 state)
{ {
return 0; return 0;
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <linux/bits.h> #include <linux/bits.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/mfd/rohm-generic.h> #include <linux/mfd/rohm-generic.h>
#include <linux/mfd/rohm-shared.h>
#include <linux/regmap.h> #include <linux/regmap.h>
enum { enum {
...@@ -89,10 +90,6 @@ struct bd70528_data { ...@@ -89,10 +90,6 @@ struct bd70528_data {
#define BD70528_REG_GPIO3_OUT 0x52 #define BD70528_REG_GPIO3_OUT 0x52
#define BD70528_REG_GPIO4_OUT 0x54 #define BD70528_REG_GPIO4_OUT 0x54
/* clk control */
#define BD70528_REG_CLK_OUT 0x2c
/* RTC */ /* RTC */
#define BD70528_REG_RTC_COUNT_H 0x2d #define BD70528_REG_RTC_COUNT_H 0x2d
...@@ -309,21 +306,8 @@ enum { ...@@ -309,21 +306,8 @@ enum {
#define BD70528_GPIO_IN_STATE_BASE 1 #define BD70528_GPIO_IN_STATE_BASE 1
#define BD70528_CLK_OUT_EN_MASK 0x1
/* RTC masks to mask out reserved bits */ /* RTC masks to mask out reserved bits */
#define BD70528_MASK_RTC_SEC 0x7f
#define BD70528_MASK_RTC_MINUTE 0x7f
#define BD70528_MASK_RTC_HOUR_24H 0x80
#define BD70528_MASK_RTC_HOUR_PM 0x20
#define BD70528_MASK_RTC_HOUR 0x1f
#define BD70528_MASK_RTC_DAY 0x3f
#define BD70528_MASK_RTC_WEEK 0x07
#define BD70528_MASK_RTC_MONTH 0x1f
#define BD70528_MASK_RTC_YEAR 0xff
#define BD70528_MASK_RTC_COUNT_L 0x7f
#define BD70528_MASK_ELAPSED_TIMER_EN 0x1 #define BD70528_MASK_ELAPSED_TIMER_EN 0x1
/* Mask second, min and hour fields /* Mask second, min and hour fields
* HW would support ALM irq for over 24h * HW would support ALM irq for over 24h
...@@ -332,7 +316,6 @@ enum { ...@@ -332,7 +316,6 @@ enum {
* wake-up we limit ALM to 24H and only * wake-up we limit ALM to 24H and only
* unmask sec, min and hour * unmask sec, min and hour
*/ */
#define BD70528_MASK_ALM_EN 0x7
#define BD70528_MASK_WAKE_EN 0x1 #define BD70528_MASK_WAKE_EN 0x1
/* WDT masks */ /* WDT masks */
......
/* SPDX-License-Identifier: GPL-2.0-or-later */
/* Copyright (C) 2019 ROHM Semiconductors */
#ifndef __LINUX_MFD_BD71828_H__
#define __LINUX_MFD_BD71828_H__
#include <linux/mfd/rohm-generic.h>
#include <linux/mfd/rohm-shared.h>
/* Regulator IDs */
enum {
BD71828_BUCK1,
BD71828_BUCK2,
BD71828_BUCK3,
BD71828_BUCK4,
BD71828_BUCK5,
BD71828_BUCK6,
BD71828_BUCK7,
BD71828_LDO1,
BD71828_LDO2,
BD71828_LDO3,
BD71828_LDO4,
BD71828_LDO5,
BD71828_LDO6,
BD71828_LDO_SNVS,
BD71828_REGULATOR_AMOUNT,
};
#define BD71828_BUCK1267_VOLTS 0xEF
#define BD71828_BUCK3_VOLTS 0x10
#define BD71828_BUCK4_VOLTS 0x20
#define BD71828_BUCK5_VOLTS 0x10
#define BD71828_LDO_VOLTS 0x32
/* LDO6 is fixed 1.8V voltage */
#define BD71828_LDO_6_VOLTAGE 1800000
/* Registers and masks*/
/* MODE control */
#define BD71828_REG_PS_CTRL_1 0x04
#define BD71828_REG_PS_CTRL_2 0x05
#define BD71828_REG_PS_CTRL_3 0x06
//#define BD71828_REG_SWRESET 0x06
#define BD71828_MASK_RUN_LVL_CTRL 0x30
/* Regulator control masks */
#define BD71828_MASK_RAMP_DELAY 0x6
#define BD71828_MASK_RUN_EN 0x08
#define BD71828_MASK_SUSP_EN 0x04
#define BD71828_MASK_IDLE_EN 0x02
#define BD71828_MASK_LPSR_EN 0x01
#define BD71828_MASK_RUN0_EN 0x01
#define BD71828_MASK_RUN1_EN 0x02
#define BD71828_MASK_RUN2_EN 0x04
#define BD71828_MASK_RUN3_EN 0x08
#define BD71828_MASK_DVS_BUCK1_CTRL 0x10
#define BD71828_DVS_BUCK1_CTRL_I2C 0
#define BD71828_DVS_BUCK1_USE_RUNLVL 0x10
#define BD71828_MASK_DVS_BUCK2_CTRL 0x20
#define BD71828_DVS_BUCK2_CTRL_I2C 0
#define BD71828_DVS_BUCK2_USE_RUNLVL 0x20
#define BD71828_MASK_DVS_BUCK6_CTRL 0x40
#define BD71828_DVS_BUCK6_CTRL_I2C 0
#define BD71828_DVS_BUCK6_USE_RUNLVL 0x40
#define BD71828_MASK_DVS_BUCK7_CTRL 0x80
#define BD71828_DVS_BUCK7_CTRL_I2C 0
#define BD71828_DVS_BUCK7_USE_RUNLVL 0x80
#define BD71828_MASK_BUCK1267_VOLT 0xff
#define BD71828_MASK_BUCK3_VOLT 0x1f
#define BD71828_MASK_BUCK4_VOLT 0x3f
#define BD71828_MASK_BUCK5_VOLT 0x1f
#define BD71828_MASK_LDO_VOLT 0x3f
/* Regulator control regs */
#define BD71828_REG_BUCK1_EN 0x08
#define BD71828_REG_BUCK1_CTRL 0x09
#define BD71828_REG_BUCK1_MODE 0x0a
#define BD71828_REG_BUCK1_IDLE_VOLT 0x0b
#define BD71828_REG_BUCK1_SUSP_VOLT 0x0c
#define BD71828_REG_BUCK1_VOLT 0x0d
#define BD71828_REG_BUCK2_EN 0x12
#define BD71828_REG_BUCK2_CTRL 0x13
#define BD71828_REG_BUCK2_MODE 0x14
#define BD71828_REG_BUCK2_IDLE_VOLT 0x15
#define BD71828_REG_BUCK2_SUSP_VOLT 0x16
#define BD71828_REG_BUCK2_VOLT 0x17
#define BD71828_REG_BUCK3_EN 0x1c
#define BD71828_REG_BUCK3_MODE 0x1d
#define BD71828_REG_BUCK3_VOLT 0x1e
#define BD71828_REG_BUCK4_EN 0x1f
#define BD71828_REG_BUCK4_MODE 0x20
#define BD71828_REG_BUCK4_VOLT 0x21
#define BD71828_REG_BUCK5_EN 0x22
#define BD71828_REG_BUCK5_MODE 0x23
#define BD71828_REG_BUCK5_VOLT 0x24
#define BD71828_REG_BUCK6_EN 0x25
#define BD71828_REG_BUCK6_CTRL 0x26
#define BD71828_REG_BUCK6_MODE 0x27
#define BD71828_REG_BUCK6_IDLE_VOLT 0x28
#define BD71828_REG_BUCK6_SUSP_VOLT 0x29
#define BD71828_REG_BUCK6_VOLT 0x2a
#define BD71828_REG_BUCK7_EN 0x2f
#define BD71828_REG_BUCK7_CTRL 0x30
#define BD71828_REG_BUCK7_MODE 0x31
#define BD71828_REG_BUCK7_IDLE_VOLT 0x32
#define BD71828_REG_BUCK7_SUSP_VOLT 0x33
#define BD71828_REG_BUCK7_VOLT 0x34
#define BD71828_REG_LDO1_EN 0x39
#define BD71828_REG_LDO1_VOLT 0x3a
#define BD71828_REG_LDO2_EN 0x3b
#define BD71828_REG_LDO2_VOLT 0x3c
#define BD71828_REG_LDO3_EN 0x3d
#define BD71828_REG_LDO3_VOLT 0x3e
#define BD71828_REG_LDO4_EN 0x3f
#define BD71828_REG_LDO4_VOLT 0x40
#define BD71828_REG_LDO5_EN 0x41
#define BD71828_REG_LDO5_VOLT 0x43
#define BD71828_REG_LDO5_VOLT_OPT 0x42
#define BD71828_REG_LDO6_EN 0x44
//#define BD71828_REG_LDO6_VOLT 0x4
#define BD71828_REG_LDO7_EN 0x45
#define BD71828_REG_LDO7_VOLT 0x46
/* GPIO */
#define BD71828_GPIO_DRIVE_MASK 0x2
#define BD71828_GPIO_OPEN_DRAIN 0x0
#define BD71828_GPIO_PUSH_PULL 0x2
#define BD71828_GPIO_OUT_HI 0x1
#define BD71828_GPIO_OUT_LO 0x0
#define BD71828_GPIO_OUT_MASK 0x1
#define BD71828_REG_GPIO_CTRL1 0x47
#define BD71828_REG_GPIO_CTRL2 0x48
#define BD71828_REG_GPIO_CTRL3 0x49
#define BD71828_REG_IO_STAT 0xed
/* RTC */
#define BD71828_REG_RTC_SEC 0x4c
#define BD71828_REG_RTC_MINUTE 0x4d
#define BD71828_REG_RTC_HOUR 0x4e
#define BD71828_REG_RTC_WEEK 0x4f
#define BD71828_REG_RTC_DAY 0x50
#define BD71828_REG_RTC_MONTH 0x51
#define BD71828_REG_RTC_YEAR 0x52
#define BD71828_REG_RTC_ALM0_SEC 0x53
#define BD71828_REG_RTC_ALM_START BD71828_REG_RTC_ALM0_SEC
#define BD71828_REG_RTC_ALM0_MINUTE 0x54
#define BD71828_REG_RTC_ALM0_HOUR 0x55
#define BD71828_REG_RTC_ALM0_WEEK 0x56
#define BD71828_REG_RTC_ALM0_DAY 0x57
#define BD71828_REG_RTC_ALM0_MONTH 0x58
#define BD71828_REG_RTC_ALM0_YEAR 0x59
#define BD71828_REG_RTC_ALM0_MASK 0x61
#define BD71828_REG_RTC_ALM1_SEC 0x5a
#define BD71828_REG_RTC_ALM1_MINUTE 0x5b
#define BD71828_REG_RTC_ALM1_HOUR 0x5c
#define BD71828_REG_RTC_ALM1_WEEK 0x5d
#define BD71828_REG_RTC_ALM1_DAY 0x5e
#define BD71828_REG_RTC_ALM1_MONTH 0x5f
#define BD71828_REG_RTC_ALM1_YEAR 0x60
#define BD71828_REG_RTC_ALM1_MASK 0x62
#define BD71828_REG_RTC_ALM2 0x63
#define BD71828_REG_RTC_START BD71828_REG_RTC_SEC
/* Charger/Battey */
#define BD71828_REG_CHG_STATE 0x65
#define BD71828_REG_CHG_FULL 0xd2
/* LEDs */
#define BD71828_REG_LED_CTRL 0x4A
#define BD71828_MASK_LED_AMBER 0x80
#define BD71828_MASK_LED_GREEN 0x40
#define BD71828_LED_ON 0xff
#define BD71828_LED_OFF 0x0
/* IRQ registers */
#define BD71828_REG_INT_MASK_BUCK 0xd3
#define BD71828_REG_INT_MASK_DCIN1 0xd4
#define BD71828_REG_INT_MASK_DCIN2 0xd5
#define BD71828_REG_INT_MASK_VSYS 0xd6
#define BD71828_REG_INT_MASK_CHG 0xd7
#define BD71828_REG_INT_MASK_BAT 0xd8
#define BD71828_REG_INT_MASK_BAT_MON1 0xd9
#define BD71828_REG_INT_MASK_BAT_MON2 0xda
#define BD71828_REG_INT_MASK_BAT_MON3 0xdb
#define BD71828_REG_INT_MASK_BAT_MON4 0xdc
#define BD71828_REG_INT_MASK_TEMP 0xdd
#define BD71828_REG_INT_MASK_RTC 0xde
#define BD71828_REG_INT_MAIN 0xdf
#define BD71828_REG_INT_BUCK 0xe0
#define BD71828_REG_INT_DCIN1 0xe1
#define BD71828_REG_INT_DCIN2 0xe2
#define BD71828_REG_INT_VSYS 0xe3
#define BD71828_REG_INT_CHG 0xe4
#define BD71828_REG_INT_BAT 0xe5
#define BD71828_REG_INT_BAT_MON1 0xe6
#define BD71828_REG_INT_BAT_MON2 0xe7
#define BD71828_REG_INT_BAT_MON3 0xe8
#define BD71828_REG_INT_BAT_MON4 0xe9
#define BD71828_REG_INT_TEMP 0xea
#define BD71828_REG_INT_RTC 0xeb
#define BD71828_REG_INT_UPDATE 0xec
#define BD71828_MAX_REGISTER BD71828_REG_IO_STAT
/* Masks for main IRQ register bits */
enum {
BD71828_INT_BUCK,
#define BD71828_INT_BUCK_MASK BIT(BD71828_INT_BUCK)
BD71828_INT_DCIN,
#define BD71828_INT_DCIN_MASK BIT(BD71828_INT_DCIN)
BD71828_INT_VSYS,
#define BD71828_INT_VSYS_MASK BIT(BD71828_INT_VSYS)
BD71828_INT_CHG,
#define BD71828_INT_CHG_MASK BIT(BD71828_INT_CHG)
BD71828_INT_BAT,
#define BD71828_INT_BAT_MASK BIT(BD71828_INT_BAT)
BD71828_INT_BAT_MON,
#define BD71828_INT_BAT_MON_MASK BIT(BD71828_INT_BAT_MON)
BD71828_INT_TEMP,
#define BD71828_INT_TEMP_MASK BIT(BD71828_INT_TEMP)
BD71828_INT_RTC,
#define BD71828_INT_RTC_MASK BIT(BD71828_INT_RTC)
};
/* Interrupts */
enum {
/* BUCK reg interrupts */
BD71828_INT_BUCK1_OCP,
BD71828_INT_BUCK2_OCP,
BD71828_INT_BUCK3_OCP,
BD71828_INT_BUCK4_OCP,
BD71828_INT_BUCK5_OCP,
BD71828_INT_BUCK6_OCP,
BD71828_INT_BUCK7_OCP,
BD71828_INT_PGFAULT,
/* DCIN1 interrupts */
BD71828_INT_DCIN_DET,
BD71828_INT_DCIN_RMV,
BD71828_INT_CLPS_OUT,
BD71828_INT_CLPS_IN,
/* DCIN2 interrupts */
BD71828_INT_DCIN_MON_RES,
BD71828_INT_DCIN_MON_DET,
BD71828_INT_LONGPUSH,
BD71828_INT_MIDPUSH,
BD71828_INT_SHORTPUSH,
BD71828_INT_PUSH,
BD71828_INT_WDOG,
BD71828_INT_SWRESET,
/* Vsys */
BD71828_INT_VSYS_UV_RES,
BD71828_INT_VSYS_UV_DET,
BD71828_INT_VSYS_LOW_RES,
BD71828_INT_VSYS_LOW_DET,
BD71828_INT_VSYS_HALL_IN,
BD71828_INT_VSYS_HALL_TOGGLE,
BD71828_INT_VSYS_MON_RES,
BD71828_INT_VSYS_MON_DET,
/* Charger */
BD71828_INT_CHG_DCIN_ILIM,
BD71828_INT_CHG_TOPOFF_TO_DONE,
BD71828_INT_CHG_WDG_TEMP,
BD71828_INT_CHG_WDG_TIME,
BD71828_INT_CHG_RECHARGE_RES,
BD71828_INT_CHG_RECHARGE_DET,
BD71828_INT_CHG_RANGED_TEMP_TRANSITION,
BD71828_INT_CHG_STATE_TRANSITION,
/* Battery */
BD71828_INT_BAT_TEMP_NORMAL,
BD71828_INT_BAT_TEMP_ERANGE,
BD71828_INT_BAT_TEMP_WARN,
BD71828_INT_BAT_REMOVED,
BD71828_INT_BAT_DETECTED,
BD71828_INT_THERM_REMOVED,
BD71828_INT_THERM_DETECTED,
/* Battery Mon 1 */
BD71828_INT_BAT_DEAD,
BD71828_INT_BAT_SHORTC_RES,
BD71828_INT_BAT_SHORTC_DET,
BD71828_INT_BAT_LOW_VOLT_RES,
BD71828_INT_BAT_LOW_VOLT_DET,
BD71828_INT_BAT_OVER_VOLT_RES,
BD71828_INT_BAT_OVER_VOLT_DET,
/* Battery Mon 2 */
BD71828_INT_BAT_MON_RES,
BD71828_INT_BAT_MON_DET,
/* Battery Mon 3 (Coulomb counter) */
BD71828_INT_BAT_CC_MON1,
BD71828_INT_BAT_CC_MON2,
BD71828_INT_BAT_CC_MON3,
/* Battery Mon 4 */
BD71828_INT_BAT_OVER_CURR_1_RES,
BD71828_INT_BAT_OVER_CURR_1_DET,
BD71828_INT_BAT_OVER_CURR_2_RES,
BD71828_INT_BAT_OVER_CURR_2_DET,
BD71828_INT_BAT_OVER_CURR_3_RES,
BD71828_INT_BAT_OVER_CURR_3_DET,
/* Temperature */
BD71828_INT_TEMP_BAT_LOW_RES,
BD71828_INT_TEMP_BAT_LOW_DET,
BD71828_INT_TEMP_BAT_HI_RES,
BD71828_INT_TEMP_BAT_HI_DET,
BD71828_INT_TEMP_CHIP_OVER_125_RES,
BD71828_INT_TEMP_CHIP_OVER_125_DET,
BD71828_INT_TEMP_CHIP_OVER_VF_DET,
BD71828_INT_TEMP_CHIP_OVER_VF_RES,
/* RTC Alarm */
BD71828_INT_RTC0,
BD71828_INT_RTC1,
BD71828_INT_RTC2,
};
#define BD71828_INT_BUCK1_OCP_MASK 0x1
#define BD71828_INT_BUCK2_OCP_MASK 0x2
#define BD71828_INT_BUCK3_OCP_MASK 0x4
#define BD71828_INT_BUCK4_OCP_MASK 0x8
#define BD71828_INT_BUCK5_OCP_MASK 0x10
#define BD71828_INT_BUCK6_OCP_MASK 0x20
#define BD71828_INT_BUCK7_OCP_MASK 0x40
#define BD71828_INT_PGFAULT_MASK 0x80
#define BD71828_INT_DCIN_DET_MASK 0x1
#define BD71828_INT_DCIN_RMV_MASK 0x2
#define BD71828_INT_CLPS_OUT_MASK 0x4
#define BD71828_INT_CLPS_IN_MASK 0x8
/* DCIN2 interrupts */
#define BD71828_INT_DCIN_MON_RES_MASK 0x1
#define BD71828_INT_DCIN_MON_DET_MASK 0x2
#define BD71828_INT_LONGPUSH_MASK 0x4
#define BD71828_INT_MIDPUSH_MASK 0x8
#define BD71828_INT_SHORTPUSH_MASK 0x10
#define BD71828_INT_PUSH_MASK 0x20
#define BD71828_INT_WDOG_MASK 0x40
#define BD71828_INT_SWRESET_MASK 0x80
/* Vsys */
#define BD71828_INT_VSYS_UV_RES_MASK 0x1
#define BD71828_INT_VSYS_UV_DET_MASK 0x2
#define BD71828_INT_VSYS_LOW_RES_MASK 0x4
#define BD71828_INT_VSYS_LOW_DET_MASK 0x8
#define BD71828_INT_VSYS_HALL_IN_MASK 0x10
#define BD71828_INT_VSYS_HALL_TOGGLE_MASK 0x20
#define BD71828_INT_VSYS_MON_RES_MASK 0x40
#define BD71828_INT_VSYS_MON_DET_MASK 0x80
/* Charger */
#define BD71828_INT_CHG_DCIN_ILIM_MASK 0x1
#define BD71828_INT_CHG_TOPOFF_TO_DONE_MASK 0x2
#define BD71828_INT_CHG_WDG_TEMP_MASK 0x4
#define BD71828_INT_CHG_WDG_TIME_MASK 0x8
#define BD71828_INT_CHG_RECHARGE_RES_MASK 0x10
#define BD71828_INT_CHG_RECHARGE_DET_MASK 0x20
#define BD71828_INT_CHG_RANGED_TEMP_TRANSITION_MASK 0x40
#define BD71828_INT_CHG_STATE_TRANSITION_MASK 0x80
/* Battery */
#define BD71828_INT_BAT_TEMP_NORMAL_MASK 0x1
#define BD71828_INT_BAT_TEMP_ERANGE_MASK 0x2
#define BD71828_INT_BAT_TEMP_WARN_MASK 0x4
#define BD71828_INT_BAT_REMOVED_MASK 0x10
#define BD71828_INT_BAT_DETECTED_MASK 0x20
#define BD71828_INT_THERM_REMOVED_MASK 0x40
#define BD71828_INT_THERM_DETECTED_MASK 0x80
/* Battery Mon 1 */
#define BD71828_INT_BAT_DEAD_MASK 0x2
#define BD71828_INT_BAT_SHORTC_RES_MASK 0x4
#define BD71828_INT_BAT_SHORTC_DET_MASK 0x8
#define BD71828_INT_BAT_LOW_VOLT_RES_MASK 0x10
#define BD71828_INT_BAT_LOW_VOLT_DET_MASK 0x20
#define BD71828_INT_BAT_OVER_VOLT_RES_MASK 0x40
#define BD71828_INT_BAT_OVER_VOLT_DET_MASK 0x80
/* Battery Mon 2 */
#define BD71828_INT_BAT_MON_RES_MASK 0x1
#define BD71828_INT_BAT_MON_DET_MASK 0x2
/* Battery Mon 3 (Coulomb counter) */
#define BD71828_INT_BAT_CC_MON1_MASK 0x1
#define BD71828_INT_BAT_CC_MON2_MASK 0x2
#define BD71828_INT_BAT_CC_MON3_MASK 0x4
/* Battery Mon 4 */
#define BD71828_INT_BAT_OVER_CURR_1_RES_MASK 0x1
#define BD71828_INT_BAT_OVER_CURR_1_DET_MASK 0x2
#define BD71828_INT_BAT_OVER_CURR_2_RES_MASK 0x4
#define BD71828_INT_BAT_OVER_CURR_2_DET_MASK 0x8
#define BD71828_INT_BAT_OVER_CURR_3_RES_MASK 0x10
#define BD71828_INT_BAT_OVER_CURR_3_DET_MASK 0x20
/* Temperature */
#define BD71828_INT_TEMP_BAT_LOW_RES_MASK 0x1
#define BD71828_INT_TEMP_BAT_LOW_DET_MASK 0x2
#define BD71828_INT_TEMP_BAT_HI_RES_MASK 0x4
#define BD71828_INT_TEMP_BAT_HI_DET_MASK 0x8
#define BD71828_INT_TEMP_CHIP_OVER_125_RES_MASK 0x10
#define BD71828_INT_TEMP_CHIP_OVER_125_DET_MASK 0x20
#define BD71828_INT_TEMP_CHIP_OVER_VF_RES_MASK 0x40
#define BD71828_INT_TEMP_CHIP_OVER_VF_DET_MASK 0x80
/* RTC Alarm */
#define BD71828_INT_RTC0_MASK 0x1
#define BD71828_INT_RTC1_MASK 0x2
#define BD71828_INT_RTC2_MASK 0x4
#define BD71828_OUT_TYPE_MASK 0x2
#define BD71828_OUT_TYPE_OPEN_DRAIN 0x0
#define BD71828_OUT_TYPE_CMOS 0x2
#endif /* __LINUX_MFD_BD71828_H__ */
...@@ -191,12 +191,6 @@ enum { ...@@ -191,12 +191,6 @@ enum {
#define IRQ_ON_REQ 0x02 #define IRQ_ON_REQ 0x02
#define IRQ_STBY_REQ 0x01 #define IRQ_STBY_REQ 0x01
/* BD718XX_REG_OUT32K bits */
#define BD718XX_OUT32K_EN 0x01
/* BD7183XX gated clock rate */
#define BD718XX_CLK_RATE 32768
/* ROHM BD718XX irqs */ /* ROHM BD718XX irqs */
enum { enum {
BD718XX_INT_STBY_REQ, BD718XX_INT_STBY_REQ,
......
...@@ -4,17 +4,83 @@ ...@@ -4,17 +4,83 @@
#ifndef __LINUX_MFD_ROHM_H__ #ifndef __LINUX_MFD_ROHM_H__
#define __LINUX_MFD_ROHM_H__ #define __LINUX_MFD_ROHM_H__
enum { #include <linux/regmap.h>
#include <linux/regulator/driver.h>
enum rohm_chip_type {
ROHM_CHIP_TYPE_BD71837 = 0, ROHM_CHIP_TYPE_BD71837 = 0,
ROHM_CHIP_TYPE_BD71847, ROHM_CHIP_TYPE_BD71847,
ROHM_CHIP_TYPE_BD70528, ROHM_CHIP_TYPE_BD70528,
ROHM_CHIP_TYPE_BD71828,
ROHM_CHIP_TYPE_AMOUNT ROHM_CHIP_TYPE_AMOUNT
}; };
struct rohm_regmap_dev { struct rohm_regmap_dev {
unsigned int chip_type;
struct device *dev; struct device *dev;
struct regmap *regmap; struct regmap *regmap;
}; };
enum {
ROHM_DVS_LEVEL_UNKNOWN,
ROHM_DVS_LEVEL_RUN,
ROHM_DVS_LEVEL_IDLE,
ROHM_DVS_LEVEL_SUSPEND,
ROHM_DVS_LEVEL_LPSR,
ROHM_DVS_LEVEL_MAX = ROHM_DVS_LEVEL_LPSR,
};
/**
* struct rohm_dvs_config - dynamic voltage scaling register descriptions
*
* @level_map: bitmap representing supported run-levels for this
* regulator
* @run_reg: register address for regulator config at 'run' state
* @run_mask: value mask for regulator voltages at 'run' state
* @run_on_mask: enable mask for regulator at 'run' state
* @idle_reg: register address for regulator config at 'idle' state
* @idle_mask: value mask for regulator voltages at 'idle' state
* @idle_on_mask: enable mask for regulator at 'idle' state
* @suspend_reg: register address for regulator config at 'suspend' state
* @suspend_mask: value mask for regulator voltages at 'suspend' state
* @suspend_on_mask: enable mask for regulator at 'suspend' state
* @lpsr_reg: register address for regulator config at 'lpsr' state
* @lpsr_mask: value mask for regulator voltages at 'lpsr' state
* @lpsr_on_mask: enable mask for regulator at 'lpsr' state
*
* Description of ROHM PMICs voltage configuration registers for different
* system states. This is used to correctly configure the PMIC at startup
* based on values read from DT.
*/
struct rohm_dvs_config {
uint64_t level_map;
unsigned int run_reg;
unsigned int run_mask;
unsigned int run_on_mask;
unsigned int idle_reg;
unsigned int idle_mask;
unsigned int idle_on_mask;
unsigned int suspend_reg;
unsigned int suspend_mask;
unsigned int suspend_on_mask;
unsigned int lpsr_reg;
unsigned int lpsr_mask;
unsigned int lpsr_on_mask;
};
#if IS_ENABLED(CONFIG_REGULATOR_ROHM)
int rohm_regulator_set_dvs_levels(const struct rohm_dvs_config *dvs,
struct device_node *np,
const struct regulator_desc *desc,
struct regmap *regmap);
#else
static inline int rohm_regulator_set_dvs_levels(const struct rohm_dvs_config *dvs,
struct device_node *np,
const struct regulator_desc *desc,
struct regmap *regmap)
{
return 0;
}
#endif
#endif #endif
/* SPDX-License-Identifier: GPL-2.0-or-later */
/* Copyright (C) 2020 ROHM Semiconductors */
#ifndef __LINUX_MFD_ROHM_SHARED_H__
#define __LINUX_MFD_ROHM_SHARED_H__
/* RTC definitions shared between BD70528 and BD71828 */
#define BD70528_MASK_RTC_SEC 0x7f
#define BD70528_MASK_RTC_MINUTE 0x7f
#define BD70528_MASK_RTC_HOUR_24H 0x80
#define BD70528_MASK_RTC_HOUR_PM 0x20
#define BD70528_MASK_RTC_HOUR 0x3f
#define BD70528_MASK_RTC_DAY 0x3f
#define BD70528_MASK_RTC_WEEK 0x07
#define BD70528_MASK_RTC_MONTH 0x1f
#define BD70528_MASK_RTC_YEAR 0xff
#define BD70528_MASK_ALM_EN 0x7
#endif /* __LINUX_MFD_ROHM_SHARED_H__ */
...@@ -23,6 +23,11 @@ extern struct regmap *syscon_regmap_lookup_by_compatible(const char *s); ...@@ -23,6 +23,11 @@ extern struct regmap *syscon_regmap_lookup_by_compatible(const char *s);
extern struct regmap *syscon_regmap_lookup_by_phandle( extern struct regmap *syscon_regmap_lookup_by_phandle(
struct device_node *np, struct device_node *np,
const char *property); const char *property);
extern struct regmap *syscon_regmap_lookup_by_phandle_args(
struct device_node *np,
const char *property,
int arg_count,
unsigned int *out_args);
#else #else
static inline struct regmap *device_node_to_regmap(struct device_node *np) static inline struct regmap *device_node_to_regmap(struct device_node *np)
{ {
...@@ -45,6 +50,15 @@ static inline struct regmap *syscon_regmap_lookup_by_phandle( ...@@ -45,6 +50,15 @@ static inline struct regmap *syscon_regmap_lookup_by_phandle(
{ {
return ERR_PTR(-ENOTSUPP); return ERR_PTR(-ENOTSUPP);
} }
static inline struct regmap *syscon_regmap_lookup_by_phandle_args(
struct device_node *np,
const char *property,
int arg_count,
unsigned int *out_args)
{
return ERR_PTR(-ENOTSUPP);
}
#endif #endif
#endif /* __LINUX_MFD_SYSCON_H__ */ #endif /* __LINUX_MFD_SYSCON_H__ */
此差异已折叠。
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __WCD934X_H__
#define __WCD934X_H__
#include <linux/clk.h>
#include <linux/regulator/consumer.h>
#include <linux/regmap.h>
#include <linux/slimbus.h>
#define WCD934X_MAX_SUPPLY 5
/**
* struct wcd934x_ddata - wcd934x driver data
*
* @supplies: wcd934x regulator supplies
* @irq_data: wcd934x irq_chip data
* @regmap: wcd934x regmap pointer
* @extclk: External clock
* @dev: device instance of wcd934x slim device
* @irq: irq for wcd934x.
*/
struct wcd934x_ddata {
struct regulator_bulk_data supplies[WCD934X_MAX_SUPPLY];
struct regmap_irq_chip_data *irq_data;
struct regmap *regmap;
struct clk *extclk;
struct device *dev;
int irq;
};
#endif /* __WCD934X_H__ */
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册