Commit f158bbee authored by Linus Torvalds's avatar Linus Torvalds

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

Pull MFD updates from Lee Jones:
 "Core Frameworks:
   - Standardise MFD_CELL_* helpers

  New Drivers:
   - Add support for Acer Iconia Tab A500 Embedded Controller

  New Device Support:
   - Add support for ROHM BD9574MWF to BD9571MWV
   - Add support for Intel Alder Lake PCH-P PCI to LPSS
   - Add support for Intel Alder Lake PCH-S PCI to LPSS

  New Functionality:
   - Support ACPI enumeration; arizona

  Fix-ups:
   - Managed resources; bd9571mwv
   - DT additions/fix-ups; bd9571mwv, iqs62x, max8997, gateworks-gsc, ene-kb930
   - Convert to SPDX; bd9571mw
   - Fix return values/error handling; sunxi
   - Provide SOFTDEP; arizona
   - Make use of DIV_ROUND_UP; mcp-sa11x0
   - Use generic APIs; arizona
   - Add MAC address sysfs entries; intel-m10-bmc
   - Trivial: Coding-style fix-ups; iqs62x
   - Trivial: Remove superflouous code; iqs62x
   - Clear-up naming conventions; iqs62x

  Bug Fixes:
   - Fix 'pointer from integer' error; altera-sysmgr
   - Convert SGI_MFD_IOC3 from tristate to bool; Kconfig
   - Fix interrupt handling; gateworks-gsc
   - Extend required delay; iqs62x
   - Do not use I2C polling during calibration; iqs62x
   - Do no adjust clock frequency during calibration; iqs62x
   - Fix use-after-free; wm831x-auxad"

* tag 'mfd-next-5.12' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd: (32 commits)
  mfd: wm831x-auxadc: Prevent use after free in wm831x_auxadc_read_irq()
  mfd: iqs62x: Do not change clock frequency during ATI
  mfd: iqs62x: Do not poll during ATI
  mfd: iqs62x: Increase interrupt handler return delay
  mfd: iqs62x: Rename regmap_config struct
  mfd: iqs62x: Remove unused bit mask
  mfd: iqs62x: Remove superfluous whitespace above fallthroughs
  mfd: intel-lpss: Add Intel Alder Lake PCH-S PCI IDs
  mfd: intel-m10-bmc: Expose MAC address and count
  mfd: Add driver for Embedded Controller found on Acer Iconia Tab A500
  dt-bindings: mfd: Add ENE KB930 Embedded Controller binding
  dt-bindings: mfd: gateworks-gsc: Add fan-tach mode
  mfd: intel-lpss: Add Intel Alder Lake PCH-P PCI IDs
  mfd: gateworks-gsc: Fix interrupt type
  mfd: Standardise MFD_CELL_* helper names
  mfd: mcp-sa11x0: Use DIV_ROUND_UP to calculate rw_timeout
  mfd: max8997: Add of_compatible to Extcon and Charger mfd_cell
  dt-bindings: mfd: Correct the node name of the panel LED
  mfd: sgi-ioc3: Turn Kconfig option into a bool
  mfd: altera-sysmgr: Fix physical address storing more
  ...
parents 4512d92b 26783d74
......@@ -13,3 +13,24 @@ Contact: Xu Yilun <yilun.xu@intel.com>
Description: Read only. Returns the firmware version of Intel MAX10
BMC chip.
Format: "0x%x".
What: /sys/bus/spi/devices/.../mac_address
Date: January 2021
KernelVersion: 5.12
Contact: Russ Weight <russell.h.weight@intel.com>
Description: Read only. Returns the first MAC address in a block
of sequential MAC addresses assigned to the board
that is managed by the Intel MAX10 BMC. It is stored in
FLASH storage and is mirrored in the MAX10 BMC register
space.
Format: "%02x:%02x:%02x:%02x:%02x:%02x".
What: /sys/bus/spi/devices/.../mac_count
Date: January 2021
KernelVersion: 5.12
Contact: Russ Weight <russell.h.weight@intel.com>
Description: Read only. Returns the number of sequential MAC
addresses assigned to the board managed by the Intel
MAX10 BMC. This value is stored in FLASH and is mirrored
in the MAX10 BMC register space.
Format: "%u".
* ROHM BD9571MWV Power Management Integrated Circuit (PMIC) bindings
* ROHM BD9571MWV/BD9574MWF Power Management Integrated Circuit (PMIC) bindings
Required properties:
- compatible : Should be "rohm,bd9571mwv".
- compatible : Should be "rohm,bd9571mwv" or "rohm,bd9574mwf".
- reg : I2C slave address.
- interrupts : The interrupt line the device is connected to.
- interrupt-controller : Marks the device node as an interrupt controller.
......
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/mfd/ene-kb930.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: ENE KB930 Embedded Controller bindings
description: |
This binding describes the ENE KB930 Embedded Controller attached to an
I2C bus.
maintainers:
- Dmitry Osipenko <digetx@gmail.com>
properties:
compatible:
items:
- enum:
- acer,a500-iconia-ec # Acer A500 Iconia tablet device
- const: ene,kb930
reg:
maxItems: 1
monitored-battery: true
power-supplies: true
system-power-controller: true
required:
- compatible
- reg
additionalProperties: false
examples:
- |
battery: battery-cell {
compatible = "simple-battery";
charge-full-design-microamp-hours = <3260000>;
energy-full-design-microwatt-hours = <24000000>;
operating-range-celsius = <0 40>;
};
mains: ac-adapter {
compatible = "gpio-charger";
charger-type = "mains";
gpios = <&gpio 125 0>;
};
i2c {
#address-cells = <1>;
#size-cells = <0>;
embedded-controller@58 {
compatible = "acer,a500-iconia-ec", "ene,kb930";
reg = <0x58>;
system-power-controller;
monitored-battery = <&battery>;
power-supplies = <&mains>;
};
};
...
......@@ -83,8 +83,9 @@ properties:
2 - scaled voltage based on an optional resistor divider
and optional offset
3 - pre-scaled 16-bit voltage value
4 - fan tach input to report RPM's
$ref: /schemas/types.yaml#/definitions/uint32
enum: [0, 1, 2, 3]
enum: [0, 1, 2, 3, 4]
gw,voltage-divider-ohms:
description: Values of resistors for divider on raw ADC input
......
......@@ -93,7 +93,7 @@ examples:
pwmleds {
compatible = "pwm-leds";
panel {
led-1 {
pwms = <&iqs620a_pwm 0 1000000>;
max-brightness = <255>;
};
......
// SPDX-License-Identifier: GPL-2.0-only
/*
* ROHM BD9571MWV-M GPIO driver
* ROHM BD9571MWV-M and BD9574MWF-M GPIO driver
*
* Copyright (C) 2017 Marek Vasut <marek.vasut+renesas@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
* kind, whether expressed or implied; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License version 2 for more details.
*
* Based on the TPS65086 driver
*
* NOTE: Interrupts are not supported yet.
*/
#include <linux/gpio/driver.h>
#include <linux/mfd/rohm-generic.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/mfd/bd9571mwv.h>
struct bd9571mwv_gpio {
struct regmap *regmap;
struct gpio_chip chip;
struct bd9571mwv *bd;
};
static int bd9571mwv_gpio_get_direction(struct gpio_chip *chip,
......@@ -34,7 +27,7 @@ static int bd9571mwv_gpio_get_direction(struct gpio_chip *chip,
struct bd9571mwv_gpio *gpio = gpiochip_get_data(chip);
int ret, val;
ret = regmap_read(gpio->bd->regmap, BD9571MWV_GPIO_DIR, &val);
ret = regmap_read(gpio->regmap, BD9571MWV_GPIO_DIR, &val);
if (ret < 0)
return ret;
if (val & BIT(offset))
......@@ -48,8 +41,7 @@ static int bd9571mwv_gpio_direction_input(struct gpio_chip *chip,
{
struct bd9571mwv_gpio *gpio = gpiochip_get_data(chip);
regmap_update_bits(gpio->bd->regmap, BD9571MWV_GPIO_DIR,
BIT(offset), 0);
regmap_update_bits(gpio->regmap, BD9571MWV_GPIO_DIR, BIT(offset), 0);
return 0;
}
......@@ -60,9 +52,9 @@ static int bd9571mwv_gpio_direction_output(struct gpio_chip *chip,
struct bd9571mwv_gpio *gpio = gpiochip_get_data(chip);
/* Set the initial value */
regmap_update_bits(gpio->bd->regmap, BD9571MWV_GPIO_OUT,
regmap_update_bits(gpio->regmap, BD9571MWV_GPIO_OUT,
BIT(offset), value ? BIT(offset) : 0);
regmap_update_bits(gpio->bd->regmap, BD9571MWV_GPIO_DIR,
regmap_update_bits(gpio->regmap, BD9571MWV_GPIO_DIR,
BIT(offset), BIT(offset));
return 0;
......@@ -73,7 +65,7 @@ static int bd9571mwv_gpio_get(struct gpio_chip *chip, unsigned int offset)
struct bd9571mwv_gpio *gpio = gpiochip_get_data(chip);
int ret, val;
ret = regmap_read(gpio->bd->regmap, BD9571MWV_GPIO_IN, &val);
ret = regmap_read(gpio->regmap, BD9571MWV_GPIO_IN, &val);
if (ret < 0)
return ret;
......@@ -85,7 +77,7 @@ static void bd9571mwv_gpio_set(struct gpio_chip *chip, unsigned int offset,
{
struct bd9571mwv_gpio *gpio = gpiochip_get_data(chip);
regmap_update_bits(gpio->bd->regmap, BD9571MWV_GPIO_OUT,
regmap_update_bits(gpio->regmap, BD9571MWV_GPIO_OUT,
BIT(offset), value ? BIT(offset) : 0);
}
......@@ -113,9 +105,9 @@ static int bd9571mwv_gpio_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, gpio);
gpio->bd = dev_get_drvdata(pdev->dev.parent);
gpio->regmap = dev_get_regmap(pdev->dev.parent, NULL);
gpio->chip = template_chip;
gpio->chip.parent = gpio->bd->dev;
gpio->chip.parent = pdev->dev.parent;
ret = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio);
if (ret < 0) {
......@@ -127,7 +119,8 @@ static int bd9571mwv_gpio_probe(struct platform_device *pdev)
}
static const struct platform_device_id bd9571mwv_gpio_id_table[] = {
{ "bd9571mwv-gpio", },
{ "bd9571mwv-gpio", ROHM_CHIP_TYPE_BD9571 },
{ "bd9574mwf-gpio", ROHM_CHIP_TYPE_BD9574 },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(platform, bd9571mwv_gpio_id_table);
......
......@@ -2085,6 +2085,17 @@ config MFD_KHADAS_MCU
additional drivers must be enabled in order to use the functionality
of the device.
config MFD_ACER_A500_EC
tristate "Support for Acer Iconia Tab A500 Embedded Controller"
depends on I2C
depends on (ARCH_TEGRA_2x_SOC && OF) || COMPILE_TEST
select MFD_CORE
select REGMAP
help
Support for Embedded Controller found on Acer Iconia Tab A500.
The controller itself is ENE KB930, it is running firmware
customized for the specific needs of the Acer A500 hardware.
menu "Multimedia Capabilities Port drivers"
depends on ARCH_SA1100
......@@ -2129,7 +2140,7 @@ config RAVE_SP_CORE
device found on several devices in RAVE line of hardware.
config SGI_MFD_IOC3
tristate "SGI IOC3 core driver"
bool "SGI IOC3 core driver"
depends on PCI && MIPS && 64BIT
select MFD_CORE
help
......
......@@ -264,6 +264,7 @@ obj-$(CONFIG_MFD_ROHM_BD71828) += rohm-bd71828.o
obj-$(CONFIG_MFD_ROHM_BD718XX) += rohm-bd718x7.o
obj-$(CONFIG_MFD_STMFX) += stmfx.o
obj-$(CONFIG_MFD_KHADAS_MCU) += khadas-mcu.o
obj-$(CONFIG_MFD_ACER_A500_EC) += acer-ec-a500.o
obj-$(CONFIG_SGI_MFD_IOC3) += ioc3.o
obj-$(CONFIG_MFD_SIMPLE_MFD_I2C) += simple-mfd-i2c.o
......
......@@ -609,52 +609,52 @@ int ab8500_suspend(struct ab8500 *ab8500)
}
static const struct mfd_cell ab8500_bm_devs[] = {
OF_MFD_CELL("ab8500-charger", NULL, &ab8500_bm_data,
MFD_CELL_OF("ab8500-charger", NULL, &ab8500_bm_data,
sizeof(ab8500_bm_data), 0, "stericsson,ab8500-charger"),
OF_MFD_CELL("ab8500-btemp", NULL, &ab8500_bm_data,
MFD_CELL_OF("ab8500-btemp", NULL, &ab8500_bm_data,
sizeof(ab8500_bm_data), 0, "stericsson,ab8500-btemp"),
OF_MFD_CELL("ab8500-fg", NULL, &ab8500_bm_data,
MFD_CELL_OF("ab8500-fg", NULL, &ab8500_bm_data,
sizeof(ab8500_bm_data), 0, "stericsson,ab8500-fg"),
OF_MFD_CELL("ab8500-chargalg", NULL, &ab8500_bm_data,
MFD_CELL_OF("ab8500-chargalg", NULL, &ab8500_bm_data,
sizeof(ab8500_bm_data), 0, "stericsson,ab8500-chargalg"),
};
static const struct mfd_cell ab8500_devs[] = {
#ifdef CONFIG_DEBUG_FS
OF_MFD_CELL("ab8500-debug",
MFD_CELL_OF("ab8500-debug",
NULL, NULL, 0, 0, "stericsson,ab8500-debug"),
#endif
OF_MFD_CELL("ab8500-sysctrl",
MFD_CELL_OF("ab8500-sysctrl",
NULL, NULL, 0, 0, "stericsson,ab8500-sysctrl"),
OF_MFD_CELL("ab8500-ext-regulator",
MFD_CELL_OF("ab8500-ext-regulator",
NULL, NULL, 0, 0, "stericsson,ab8500-ext-regulator"),
OF_MFD_CELL("ab8500-regulator",
MFD_CELL_OF("ab8500-regulator",
NULL, NULL, 0, 0, "stericsson,ab8500-regulator"),
OF_MFD_CELL("ab8500-clk",
MFD_CELL_OF("ab8500-clk",
NULL, NULL, 0, 0, "stericsson,ab8500-clk"),
OF_MFD_CELL("ab8500-gpadc",
MFD_CELL_OF("ab8500-gpadc",
NULL, NULL, 0, 0, "stericsson,ab8500-gpadc"),
OF_MFD_CELL("ab8500-rtc",
MFD_CELL_OF("ab8500-rtc",
NULL, NULL, 0, 0, "stericsson,ab8500-rtc"),
OF_MFD_CELL("ab8500-acc-det",
MFD_CELL_OF("ab8500-acc-det",
NULL, NULL, 0, 0, "stericsson,ab8500-acc-det"),
OF_MFD_CELL("ab8500-poweron-key",
MFD_CELL_OF("ab8500-poweron-key",
NULL, NULL, 0, 0, "stericsson,ab8500-poweron-key"),
OF_MFD_CELL("ab8500-pwm",
MFD_CELL_OF("ab8500-pwm",
NULL, NULL, 0, 1, "stericsson,ab8500-pwm"),
OF_MFD_CELL("ab8500-pwm",
MFD_CELL_OF("ab8500-pwm",
NULL, NULL, 0, 2, "stericsson,ab8500-pwm"),
OF_MFD_CELL("ab8500-pwm",
MFD_CELL_OF("ab8500-pwm",
NULL, NULL, 0, 3, "stericsson,ab8500-pwm"),
OF_MFD_CELL("ab8500-denc",
MFD_CELL_OF("ab8500-denc",
NULL, NULL, 0, 0, "stericsson,ab8500-denc"),
OF_MFD_CELL("pinctrl-ab8500",
MFD_CELL_OF("pinctrl-ab8500",
NULL, NULL, 0, 0, "stericsson,ab8500-gpio"),
OF_MFD_CELL("abx500-temp",
MFD_CELL_OF("abx500-temp",
NULL, NULL, 0, 0, "stericsson,abx500-temp"),
OF_MFD_CELL("ab8500-usb",
MFD_CELL_OF("ab8500-usb",
NULL, NULL, 0, 0, "stericsson,ab8500-usb"),
OF_MFD_CELL("ab8500-codec",
MFD_CELL_OF("ab8500-codec",
NULL, NULL, 0, 0, "stericsson,ab8500-codec"),
};
......
// SPDX-License-Identifier: GPL-2.0+
/*
* Acer Iconia Tab A500 Embedded Controller Driver
*
* Copyright 2020 GRATE-driver project
*/
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/mfd/core.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/reboot.h>
#include <linux/regmap.h>
#define A500_EC_I2C_ERR_TIMEOUT 500
#define A500_EC_POWER_CMD_TIMEOUT 1000
/*
* Controller's firmware expects specific command opcodes to be used for the
* corresponding registers. Unsupported commands are skipped by the firmware.
*/
#define CMD_SHUTDOWN 0x0
#define CMD_WARM_REBOOT 0x0
#define CMD_COLD_REBOOT 0x1
enum {
REG_CURRENT_NOW = 0x03,
REG_SHUTDOWN = 0x52,
REG_WARM_REBOOT = 0x54,
REG_COLD_REBOOT = 0x55,
};
static struct i2c_client *a500_ec_client_pm_off;
static int a500_ec_read(void *context, const void *reg_buf, size_t reg_size,
void *val_buf, size_t val_sizel)
{
struct i2c_client *client = context;
unsigned int reg, retries = 5;
u16 *ret_val = val_buf;
s32 ret = 0;
reg = *(u8 *)reg_buf;
while (retries-- > 0) {
ret = i2c_smbus_read_word_data(client, reg);
if (ret >= 0)
break;
msleep(A500_EC_I2C_ERR_TIMEOUT);
}
if (ret < 0) {
dev_err(&client->dev, "read 0x%x failed: %d\n", reg, ret);
return ret;
}
*ret_val = ret;
if (reg == REG_CURRENT_NOW)
fsleep(10000);
return 0;
}
static int a500_ec_write(void *context, const void *data, size_t count)
{
struct i2c_client *client = context;
unsigned int reg, val, retries = 5;
s32 ret = 0;
reg = *(u8 *)(data + 0);
val = *(u16 *)(data + 1);
while (retries-- > 0) {
ret = i2c_smbus_write_word_data(client, reg, val);
if (ret >= 0)
break;
msleep(A500_EC_I2C_ERR_TIMEOUT);
}
if (ret < 0) {
dev_err(&client->dev, "write 0x%x failed: %d\n", reg, ret);
return ret;
}
return 0;
}
static const struct regmap_config a500_ec_regmap_config = {
.name = "KB930",
.reg_bits = 8,
.val_bits = 16,
.max_register = 0xff,
};
static const struct regmap_bus a500_ec_regmap_bus = {
.reg_format_endian_default = REGMAP_ENDIAN_NATIVE,
.val_format_endian_default = REGMAP_ENDIAN_LITTLE,
.write = a500_ec_write,
.read = a500_ec_read,
.max_raw_read = 2,
};
static void a500_ec_poweroff(void)
{
i2c_smbus_write_word_data(a500_ec_client_pm_off,
REG_SHUTDOWN, CMD_SHUTDOWN);
mdelay(A500_EC_POWER_CMD_TIMEOUT);
}
static int a500_ec_restart_notify(struct notifier_block *this,
unsigned long reboot_mode, void *data)
{
if (reboot_mode == REBOOT_WARM)
i2c_smbus_write_word_data(a500_ec_client_pm_off,
REG_WARM_REBOOT, CMD_WARM_REBOOT);
else
i2c_smbus_write_word_data(a500_ec_client_pm_off,
REG_COLD_REBOOT, CMD_COLD_REBOOT);
mdelay(A500_EC_POWER_CMD_TIMEOUT);
return NOTIFY_DONE;
}
static struct notifier_block a500_ec_restart_handler = {
.notifier_call = a500_ec_restart_notify,
.priority = 200,
};
static const struct mfd_cell a500_ec_cells[] = {
{ .name = "acer-a500-iconia-battery", },
{ .name = "acer-a500-iconia-leds", },
};
static int a500_ec_probe(struct i2c_client *client)
{
struct regmap *regmap;
int err;
regmap = devm_regmap_init(&client->dev, &a500_ec_regmap_bus,
client, &a500_ec_regmap_config);
if (IS_ERR(regmap))
return PTR_ERR(regmap);
err = devm_mfd_add_devices(&client->dev, PLATFORM_DEVID_AUTO,
a500_ec_cells, ARRAY_SIZE(a500_ec_cells),
NULL, 0, NULL);
if (err) {
dev_err(&client->dev, "failed to add sub-devices: %d\n", err);
return err;
}
if (of_device_is_system_power_controller(client->dev.of_node)) {
a500_ec_client_pm_off = client;
err = register_restart_handler(&a500_ec_restart_handler);
if (err)
return err;
if (!pm_power_off)
pm_power_off = a500_ec_poweroff;
}
return 0;
}
static int a500_ec_remove(struct i2c_client *client)
{
if (of_device_is_system_power_controller(client->dev.of_node)) {
if (pm_power_off == a500_ec_poweroff)
pm_power_off = NULL;
unregister_restart_handler(&a500_ec_restart_handler);
}
return 0;
}
static const struct of_device_id a500_ec_match[] = {
{ .compatible = "acer,a500-iconia-ec" },
{ }
};
MODULE_DEVICE_TABLE(of, a500_ec_match);
static struct i2c_driver a500_ec_driver = {
.driver = {
.name = "acer-a500-embedded-controller",
.of_match_table = a500_ec_match,
},
.probe_new = a500_ec_probe,
.remove = a500_ec_remove,
};
module_i2c_driver(a500_ec_driver);
MODULE_DESCRIPTION("Acer Iconia Tab A500 Embedded Controller driver");
MODULE_AUTHOR("Dmitry Osipenko <digetx@gmail.com>");
MODULE_LICENSE("GPL");
......@@ -145,7 +145,8 @@ static int sysmgr_probe(struct platform_device *pdev)
sysmgr_config.reg_write = s10_protected_reg_write;
/* Need physical address for SMCC call */
regmap = devm_regmap_init(dev, NULL, (void *)res->start,
regmap = devm_regmap_init(dev, NULL,
(void *)(uintptr_t)res->start,
&sysmgr_config);
} else {
base = devm_ioremap(dev, res->start, resource_size(res));
......
// SPDX-License-Identifier: GPL-2.0-only
/*
* ROHM BD9571MWV-M MFD driver
* ROHM BD9571MWV-M and BD9574MVF-M core driver
*
* Copyright (C) 2017 Marek Vasut <marek.vasut+renesas@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
* kind, whether expressed or implied; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License version 2 for more details.
* Copyright (C) 2020 Renesas Electronics Corporation
*
* Based on the TPS65086 driver
*/
......@@ -18,6 +11,7 @@
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/mfd/core.h>
#include <linux/mfd/rohm-generic.h>
#include <linux/module.h>
#include <linux/mfd/bd9571mwv.h>
......@@ -110,13 +104,78 @@ static struct regmap_irq_chip bd9571mwv_irq_chip = {
.num_irqs = ARRAY_SIZE(bd9571mwv_irqs),
};
static int bd9571mwv_identify(struct bd9571mwv *bd)
static const struct mfd_cell bd9574mwf_cells[] = {
{ .name = "bd9574mwf-regulator", },
{ .name = "bd9574mwf-gpio", },
};
static const struct regmap_range bd9574mwf_readable_yes_ranges[] = {
regmap_reg_range(BD9571MWV_VENDOR_CODE, BD9571MWV_PRODUCT_REVISION),
regmap_reg_range(BD9571MWV_BKUP_MODE_CNT, BD9571MWV_BKUP_MODE_CNT),
regmap_reg_range(BD9571MWV_DVFS_VINIT, BD9571MWV_DVFS_SETVMAX),
regmap_reg_range(BD9571MWV_DVFS_SETVID, BD9571MWV_DVFS_MONIVDAC),
regmap_reg_range(BD9571MWV_GPIO_IN, BD9571MWV_GPIO_IN),
regmap_reg_range(BD9571MWV_GPIO_INT, BD9571MWV_GPIO_INTMASK),
regmap_reg_range(BD9571MWV_INT_INTREQ, BD9571MWV_INT_INTMASK),
};
static const struct regmap_access_table bd9574mwf_readable_table = {
.yes_ranges = bd9574mwf_readable_yes_ranges,
.n_yes_ranges = ARRAY_SIZE(bd9574mwf_readable_yes_ranges),
};
static const struct regmap_range bd9574mwf_writable_yes_ranges[] = {
regmap_reg_range(BD9571MWV_BKUP_MODE_CNT, BD9571MWV_BKUP_MODE_CNT),
regmap_reg_range(BD9571MWV_DVFS_SETVID, BD9571MWV_DVFS_SETVID),
regmap_reg_range(BD9571MWV_GPIO_DIR, BD9571MWV_GPIO_OUT),
regmap_reg_range(BD9571MWV_GPIO_INT_SET, BD9571MWV_GPIO_INTMASK),
regmap_reg_range(BD9571MWV_INT_INTREQ, BD9571MWV_INT_INTMASK),
};
static const struct regmap_access_table bd9574mwf_writable_table = {
.yes_ranges = bd9574mwf_writable_yes_ranges,
.n_yes_ranges = ARRAY_SIZE(bd9574mwf_writable_yes_ranges),
};
static const struct regmap_range bd9574mwf_volatile_yes_ranges[] = {
regmap_reg_range(BD9571MWV_DVFS_MONIVDAC, BD9571MWV_DVFS_MONIVDAC),
regmap_reg_range(BD9571MWV_GPIO_IN, BD9571MWV_GPIO_IN),
regmap_reg_range(BD9571MWV_GPIO_INT, BD9571MWV_GPIO_INT),
regmap_reg_range(BD9571MWV_INT_INTREQ, BD9571MWV_INT_INTREQ),
};
static const struct regmap_access_table bd9574mwf_volatile_table = {
.yes_ranges = bd9574mwf_volatile_yes_ranges,
.n_yes_ranges = ARRAY_SIZE(bd9574mwf_volatile_yes_ranges),
};
static const struct regmap_config bd9574mwf_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.cache_type = REGCACHE_RBTREE,
.rd_table = &bd9574mwf_readable_table,
.wr_table = &bd9574mwf_writable_table,
.volatile_table = &bd9574mwf_volatile_table,
.max_register = 0xff,
};
static struct regmap_irq_chip bd9574mwf_irq_chip = {
.name = "bd9574mwf",
.status_base = BD9571MWV_INT_INTREQ,
.mask_base = BD9571MWV_INT_INTMASK,
.ack_base = BD9571MWV_INT_INTREQ,
.init_ack_masked = true,
.num_regs = 1,
.irqs = bd9571mwv_irqs,
.num_irqs = ARRAY_SIZE(bd9571mwv_irqs),
};
static int bd957x_identify(struct device *dev, struct regmap *regmap)
{
struct device *dev = bd->dev;
unsigned int value;
int ret;
ret = regmap_read(bd->regmap, BD9571MWV_VENDOR_CODE, &value);
ret = regmap_read(regmap, BD9571MWV_VENDOR_CODE, &value);
if (ret) {
dev_err(dev, "Failed to read vendor code register (ret=%i)\n",
ret);
......@@ -129,84 +188,82 @@ static int bd9571mwv_identify(struct bd9571mwv *bd)
return -EINVAL;
}
ret = regmap_read(bd->regmap, BD9571MWV_PRODUCT_CODE, &value);
ret = regmap_read(regmap, BD9571MWV_PRODUCT_CODE, &value);
if (ret) {
dev_err(dev, "Failed to read product code register (ret=%i)\n",
ret);
return ret;
}
if (value != BD9571MWV_PRODUCT_CODE_VAL) {
dev_err(dev, "Invalid product code ID %02x (expected %02x)\n",
value, BD9571MWV_PRODUCT_CODE_VAL);
return -EINVAL;
}
ret = regmap_read(bd->regmap, BD9571MWV_PRODUCT_REVISION, &value);
ret = regmap_read(regmap, BD9571MWV_PRODUCT_REVISION, &value);
if (ret) {
dev_err(dev, "Failed to read revision register (ret=%i)\n",
ret);
return ret;
}
dev_info(dev, "Device: BD9571MWV rev. %d\n", value & 0xff);
return 0;
}
static int bd9571mwv_probe(struct i2c_client *client,
const struct i2c_device_id *ids)
const struct i2c_device_id *ids)
{
struct bd9571mwv *bd;
int ret;
bd = devm_kzalloc(&client->dev, sizeof(*bd), GFP_KERNEL);
if (!bd)
return -ENOMEM;
const struct regmap_config *regmap_config;
const struct regmap_irq_chip *irq_chip;
const struct mfd_cell *cells;
struct device *dev = &client->dev;
struct regmap *regmap;
struct regmap_irq_chip_data *irq_data;
int ret, num_cells, irq = client->irq;
/* Read the PMIC product code */
ret = i2c_smbus_read_byte_data(client, BD9571MWV_PRODUCT_CODE);
if (ret < 0) {
dev_err(dev, "Failed to read product code\n");
return ret;
}
i2c_set_clientdata(client, bd);
bd->dev = &client->dev;
bd->irq = client->irq;
switch (ret) {
case BD9571MWV_PRODUCT_CODE_BD9571MWV:
regmap_config = &bd9571mwv_regmap_config;
irq_chip = &bd9571mwv_irq_chip;
cells = bd9571mwv_cells;
num_cells = ARRAY_SIZE(bd9571mwv_cells);
break;
case BD9571MWV_PRODUCT_CODE_BD9574MWF:
regmap_config = &bd9574mwf_regmap_config;
irq_chip = &bd9574mwf_irq_chip;
cells = bd9574mwf_cells;
num_cells = ARRAY_SIZE(bd9574mwf_cells);
break;
default:
dev_err(dev, "Unsupported device 0x%x\n", ret);
return -ENODEV;
}
bd->regmap = devm_regmap_init_i2c(client, &bd9571mwv_regmap_config);
if (IS_ERR(bd->regmap)) {
dev_err(bd->dev, "Failed to initialize register map\n");
return PTR_ERR(bd->regmap);
regmap = devm_regmap_init_i2c(client, regmap_config);
if (IS_ERR(regmap)) {
dev_err(dev, "Failed to initialize register map\n");
return PTR_ERR(regmap);
}
ret = bd9571mwv_identify(bd);
ret = bd957x_identify(dev, regmap);
if (ret)
return ret;
ret = regmap_add_irq_chip(bd->regmap, bd->irq, IRQF_ONESHOT, 0,
&bd9571mwv_irq_chip, &bd->irq_data);
if (ret) {
dev_err(bd->dev, "Failed to register IRQ chip\n");
return ret;
}
ret = mfd_add_devices(bd->dev, PLATFORM_DEVID_AUTO, bd9571mwv_cells,
ARRAY_SIZE(bd9571mwv_cells), NULL, 0,
regmap_irq_get_domain(bd->irq_data));
ret = devm_regmap_add_irq_chip(dev, regmap, irq, IRQF_ONESHOT, 0,
irq_chip, &irq_data);
if (ret) {
regmap_del_irq_chip(bd->irq, bd->irq_data);
dev_err(dev, "Failed to register IRQ chip\n");
return ret;
}
return 0;
}
static int bd9571mwv_remove(struct i2c_client *client)
{
struct bd9571mwv *bd = i2c_get_clientdata(client);
regmap_del_irq_chip(bd->irq, bd->irq_data);
return 0;
return devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, cells, num_cells,
NULL, 0, regmap_irq_get_domain(irq_data));
}
static const struct of_device_id bd9571mwv_of_match_table[] = {
{ .compatible = "rohm,bd9571mwv", },
{ .compatible = "rohm,bd9574mwf", },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, bd9571mwv_of_match_table);
......@@ -223,7 +280,6 @@ static struct i2c_driver bd9571mwv_driver = {
.of_match_table = bd9571mwv_of_match_table,
},
.probe = bd9571mwv_probe,
.remove = bd9571mwv_remove,
.id_table = bd9571mwv_id_table,
};
module_i2c_driver(bd9571mwv_driver);
......
......@@ -2954,12 +2954,12 @@ static const struct mfd_cell common_prcmu_devs[] = {
};
static const struct mfd_cell db8500_prcmu_devs[] = {
OF_MFD_CELL("db8500-prcmu-regulators", NULL,
MFD_CELL_OF("db8500-prcmu-regulators", NULL,
&db8500_regulators, sizeof(db8500_regulators), 0,
"stericsson,db8500-prcmu-regulator"),
OF_MFD_CELL("cpuidle-dbx500",
MFD_CELL_OF("cpuidle-dbx500",
NULL, NULL, 0, 0, "stericsson,cpuidle-dbx500"),
OF_MFD_CELL("db8500-thermal",
MFD_CELL_OF("db8500-thermal",
NULL, NULL, 0, 0, "stericsson,db8500-thermal"),
};
......
......@@ -234,7 +234,7 @@ static int gsc_probe(struct i2c_client *client)
ret = devm_regmap_add_irq_chip(dev, gsc->regmap, client->irq,
IRQF_ONESHOT | IRQF_SHARED |
IRQF_TRIGGER_FALLING, 0,
IRQF_TRIGGER_LOW, 0,
&gsc_irq_chip, &irq_data);
if (ret)
return ret;
......
......@@ -277,6 +277,19 @@ static const struct pci_device_id intel_lpss_pci_ids[] = {
{ 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 },
/* ADL-P */
{ PCI_VDEVICE(INTEL, 0x51a8), (kernel_ulong_t)&bxt_uart_info },
{ PCI_VDEVICE(INTEL, 0x51a9), (kernel_ulong_t)&bxt_uart_info },
{ PCI_VDEVICE(INTEL, 0x51aa), (kernel_ulong_t)&bxt_info },
{ PCI_VDEVICE(INTEL, 0x51ab), (kernel_ulong_t)&bxt_info },
{ PCI_VDEVICE(INTEL, 0x51c5), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x51c6), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x51c7), (kernel_ulong_t)&bxt_uart_info },
{ PCI_VDEVICE(INTEL, 0x51e8), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x51e9), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x51ea), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x51eb), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x51fb), (kernel_ulong_t)&bxt_info },
/* APL */
{ PCI_VDEVICE(INTEL, 0x5aac), (kernel_ulong_t)&apl_i2c_info },
{ PCI_VDEVICE(INTEL, 0x5aae), (kernel_ulong_t)&apl_i2c_info },
......@@ -293,6 +306,21 @@ static const struct pci_device_id intel_lpss_pci_ids[] = {
{ PCI_VDEVICE(INTEL, 0x5ac4), (kernel_ulong_t)&bxt_info },
{ PCI_VDEVICE(INTEL, 0x5ac6), (kernel_ulong_t)&bxt_info },
{ PCI_VDEVICE(INTEL, 0x5aee), (kernel_ulong_t)&bxt_uart_info },
/* ADL-S */
{ PCI_VDEVICE(INTEL, 0x7aa8), (kernel_ulong_t)&bxt_uart_info },
{ PCI_VDEVICE(INTEL, 0x7aa9), (kernel_ulong_t)&bxt_uart_info },
{ PCI_VDEVICE(INTEL, 0x7aaa), (kernel_ulong_t)&bxt_info },
{ PCI_VDEVICE(INTEL, 0x7aab), (kernel_ulong_t)&bxt_info },
{ PCI_VDEVICE(INTEL, 0x7acc), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x7acd), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x7ace), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x7acf), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x7adc), (kernel_ulong_t)&bxt_uart_info },
{ PCI_VDEVICE(INTEL, 0x7af9), (kernel_ulong_t)&bxt_info },
{ PCI_VDEVICE(INTEL, 0x7afb), (kernel_ulong_t)&bxt_info },
{ PCI_VDEVICE(INTEL, 0x7afc), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x7afd), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x7afe), (kernel_ulong_t)&bxt_uart_info },
/* LKF */
{ PCI_VDEVICE(INTEL, 0x98a8), (kernel_ulong_t)&bxt_uart_info },
{ PCI_VDEVICE(INTEL, 0x98a9), (kernel_ulong_t)&bxt_uart_info },
......
......@@ -60,9 +60,52 @@ static ssize_t bmcfw_version_show(struct device *dev,
}
static DEVICE_ATTR_RO(bmcfw_version);
static ssize_t mac_address_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct intel_m10bmc *max10 = dev_get_drvdata(dev);
unsigned int macaddr_low, macaddr_high;
int ret;
ret = m10bmc_sys_read(max10, M10BMC_MAC_LOW, &macaddr_low);
if (ret)
return ret;
ret = m10bmc_sys_read(max10, M10BMC_MAC_HIGH, &macaddr_high);
if (ret)
return ret;
return sysfs_emit(buf, "%02x:%02x:%02x:%02x:%02x:%02x\n",
(u8)FIELD_GET(M10BMC_MAC_BYTE1, macaddr_low),
(u8)FIELD_GET(M10BMC_MAC_BYTE2, macaddr_low),
(u8)FIELD_GET(M10BMC_MAC_BYTE3, macaddr_low),
(u8)FIELD_GET(M10BMC_MAC_BYTE4, macaddr_low),
(u8)FIELD_GET(M10BMC_MAC_BYTE5, macaddr_high),
(u8)FIELD_GET(M10BMC_MAC_BYTE6, macaddr_high));
}
static DEVICE_ATTR_RO(mac_address);
static ssize_t mac_count_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct intel_m10bmc *max10 = dev_get_drvdata(dev);
unsigned int macaddr_high;
int ret;
ret = m10bmc_sys_read(max10, M10BMC_MAC_HIGH, &macaddr_high);
if (ret)
return ret;
return sysfs_emit(buf, "%u\n",
(u8)FIELD_GET(M10BMC_MAC_COUNT, macaddr_high));
}
static DEVICE_ATTR_RO(mac_count);
static struct attribute *m10bmc_attrs[] = {
&dev_attr_bmc_version.attr,
&dev_attr_bmcfw_version.attr,
&dev_attr_mac_address.attr,
&dev_attr_mac_count.attr,
NULL,
};
ATTRIBUTE_GROUPS(m10bmc);
......
......@@ -36,7 +36,6 @@
#define IQS62X_PROD_NUM 0x00
#define IQS62X_SYS_FLAGS 0x10
#define IQS62X_SYS_FLAGS_IN_ATI BIT(2)
#define IQS620_HALL_FLAGS 0x16
#define IQS621_HALL_FLAGS 0x19
......@@ -57,10 +56,10 @@
#define IQS620_TEMP_CAL_OFFS 0xC4
#define IQS62X_SYS_SETTINGS 0xD0
#define IQS62X_SYS_SETTINGS_SOFT_RESET BIT(7)
#define IQS62X_SYS_SETTINGS_ACK_RESET BIT(6)
#define IQS62X_SYS_SETTINGS_EVENT_MODE BIT(5)
#define IQS62X_SYS_SETTINGS_CLK_DIV BIT(4)
#define IQS62X_SYS_SETTINGS_COMM_ATI BIT(3)
#define IQS62X_SYS_SETTINGS_REDO_ATI BIT(1)
#define IQS62X_PWR_SETTINGS 0xD2
......@@ -82,9 +81,8 @@
#define IQS62X_FW_REC_TYPE_MASK 3
#define IQS62X_FW_REC_TYPE_DATA 4
#define IQS62X_ATI_POLL_SLEEP_US 10000
#define IQS62X_ATI_POLL_TIMEOUT_US 500000
#define IQS62X_ATI_STABLE_DELAY_MS 150
#define IQS62X_ATI_STARTUP_MS 350
#define IQS62X_FILT_SETTLE_MS 250
struct iqs62x_fw_rec {
u8 type;
......@@ -112,9 +110,16 @@ static int iqs62x_dev_init(struct iqs62x_core *iqs62x)
struct iqs62x_fw_blk *fw_blk;
unsigned int val;
int ret;
u8 clk_div = 1;
list_for_each_entry(fw_blk, &iqs62x->fw_blk_head, list) {
/*
* In case ATI is in progress, wait for it to complete before
* lowering the core clock frequency.
*/
if (fw_blk->addr == IQS62X_SYS_SETTINGS &&
*fw_blk->data & IQS62X_SYS_SETTINGS_CLK_DIV)
msleep(IQS62X_ATI_STARTUP_MS);
if (fw_blk->mask)
ret = regmap_update_bits(iqs62x->regmap, fw_blk->addr,
fw_blk->mask, *fw_blk->data);
......@@ -135,7 +140,6 @@ static int iqs62x_dev_init(struct iqs62x_core *iqs62x)
if (val & IQS620_PROX_SETTINGS_4_SAR_EN)
iqs62x->ui_sel = IQS62X_UI_SAR1;
fallthrough;
case IQS621_PROD_NUM:
......@@ -183,28 +187,32 @@ static int iqs62x_dev_init(struct iqs62x_core *iqs62x)
return ret;
}
ret = regmap_read(iqs62x->regmap, IQS62X_SYS_SETTINGS, &val);
if (ret)
return ret;
if (val & IQS62X_SYS_SETTINGS_CLK_DIV)
clk_div = iqs62x->dev_desc->clk_div;
ret = regmap_write(iqs62x->regmap, IQS62X_SYS_SETTINGS, val |
IQS62X_SYS_SETTINGS_ACK_RESET |
IQS62X_SYS_SETTINGS_EVENT_MODE |
IQS62X_SYS_SETTINGS_REDO_ATI);
if (ret)
return ret;
ret = regmap_read_poll_timeout(iqs62x->regmap, IQS62X_SYS_FLAGS, val,
!(val & IQS62X_SYS_FLAGS_IN_ATI),
IQS62X_ATI_POLL_SLEEP_US,
IQS62X_ATI_POLL_TIMEOUT_US * clk_div);
/*
* Place the device in streaming mode at first so as not to miss the
* limited number of interrupts that would otherwise occur after ATI
* completes. The device is subsequently placed in event mode by the
* interrupt handler.
*
* In the meantime, mask interrupts during ATI to prevent the device
* from soliciting I2C traffic until the noise-sensitive ATI process
* is complete.
*/
ret = regmap_update_bits(iqs62x->regmap, IQS62X_SYS_SETTINGS,
IQS62X_SYS_SETTINGS_ACK_RESET |
IQS62X_SYS_SETTINGS_EVENT_MODE |
IQS62X_SYS_SETTINGS_COMM_ATI |
IQS62X_SYS_SETTINGS_REDO_ATI,
IQS62X_SYS_SETTINGS_ACK_RESET |
IQS62X_SYS_SETTINGS_REDO_ATI);
if (ret)
return ret;
msleep(IQS62X_ATI_STABLE_DELAY_MS * clk_div);
/*
* The following delay gives the device time to deassert its RDY output
* in case a communication window was open while the REDO_ATI field was
* written. This prevents an interrupt from being serviced prematurely.
*/
usleep_range(5000, 5100);
return 0;
}
......@@ -435,6 +443,11 @@ const struct iqs62x_event_desc iqs62x_events[IQS62X_NUM_EVENTS] = {
.mask = BIT(7),
.val = BIT(7),
},
[IQS62X_EVENT_SYS_ATI] = {
.reg = IQS62X_EVENT_SYS,
.mask = BIT(2),
.val = BIT(2),
},
};
EXPORT_SYMBOL_GPL(iqs62x_events);
......@@ -469,7 +482,6 @@ static irqreturn_t iqs62x_irq(int irq, void *context)
switch (event_reg) {
case IQS62X_EVENT_UI_LO:
event_data.ui_data = get_unaligned_le16(&event_map[i]);
fallthrough;
case IQS62X_EVENT_UI_HI:
......@@ -490,7 +502,6 @@ static irqreturn_t iqs62x_irq(int irq, void *context)
case IQS62X_EVENT_HYST:
event_map[i] <<= iqs62x->dev_desc->hyst_shift;
fallthrough;
case IQS62X_EVENT_WHEEL:
......@@ -525,19 +536,46 @@ static irqreturn_t iqs62x_irq(int irq, void *context)
"Failed to re-initialize device: %d\n", ret);
return IRQ_NONE;
}
iqs62x->event_cache |= BIT(IQS62X_EVENT_SYS_RESET);
reinit_completion(&iqs62x->ati_done);
} else if (event_flags & BIT(IQS62X_EVENT_SYS_ATI)) {
iqs62x->event_cache |= BIT(IQS62X_EVENT_SYS_ATI);
reinit_completion(&iqs62x->ati_done);
} else if (!completion_done(&iqs62x->ati_done)) {
ret = regmap_update_bits(iqs62x->regmap, IQS62X_SYS_SETTINGS,
IQS62X_SYS_SETTINGS_EVENT_MODE, 0xFF);
if (ret) {
dev_err(&client->dev,
"Failed to enable event mode: %d\n", ret);
return IRQ_NONE;
}
msleep(IQS62X_FILT_SETTLE_MS);
complete_all(&iqs62x->ati_done);
}
ret = blocking_notifier_call_chain(&iqs62x->nh, event_flags,
&event_data);
if (ret & NOTIFY_STOP_MASK)
return IRQ_NONE;
/*
* Reset and ATI events are not broadcast to the sub-device drivers
* until ATI has completed. Any other events that may have occurred
* during ATI are ignored.
*/
if (completion_done(&iqs62x->ati_done)) {
event_flags |= iqs62x->event_cache;
ret = blocking_notifier_call_chain(&iqs62x->nh, event_flags,
&event_data);
if (ret & NOTIFY_STOP_MASK)
return IRQ_NONE;
iqs62x->event_cache = 0;
}
/*
* Once the communication window is closed, a small delay is added to
* ensure the device's RDY output has been deasserted by the time the
* interrupt handler returns.
*/
usleep_range(50, 100);
usleep_range(150, 200);
return IRQ_HANDLED;
}
......@@ -571,6 +609,12 @@ static void iqs62x_firmware_load(const struct firmware *fw, void *context)
goto err_out;
}
if (!wait_for_completion_timeout(&iqs62x->ati_done,
msecs_to_jiffies(2000))) {
dev_err(&client->dev, "Failed to complete ATI\n");
goto err_out;
}
ret = devm_mfd_add_devices(&client->dev, PLATFORM_DEVID_NONE,
iqs62x->dev_desc->sub_devs,
iqs62x->dev_desc->num_sub_devs,
......@@ -752,22 +796,17 @@ static const struct iqs62x_dev_desc iqs62x_devs[] = {
.dev_name = "iqs620at",
.sub_devs = iqs620at_sub_devs,
.num_sub_devs = ARRAY_SIZE(iqs620at_sub_devs),
.prod_num = IQS620_PROD_NUM,
.sw_num = 0x08,
.cal_regs = iqs620at_cal_regs,
.num_cal_regs = ARRAY_SIZE(iqs620at_cal_regs),
.prox_mask = BIT(0),
.sar_mask = BIT(1) | BIT(7),
.hall_mask = BIT(2),
.hyst_mask = BIT(3),
.temp_mask = BIT(4),
.prox_settings = IQS620_PROX_SETTINGS_4,
.hall_flags = IQS620_HALL_FLAGS,
.clk_div = 4,
.fw_name = "iqs620a.bin",
.event_regs = &iqs620a_event_regs[IQS62X_UI_PROX],
},
......@@ -775,20 +814,15 @@ static const struct iqs62x_dev_desc iqs62x_devs[] = {
.dev_name = "iqs620a",
.sub_devs = iqs620a_sub_devs,
.num_sub_devs = ARRAY_SIZE(iqs620a_sub_devs),
.prod_num = IQS620_PROD_NUM,
.sw_num = 0x08,
.prox_mask = BIT(0),
.sar_mask = BIT(1) | BIT(7),
.hall_mask = BIT(2),
.hyst_mask = BIT(3),
.temp_mask = BIT(4),
.prox_settings = IQS620_PROX_SETTINGS_4,
.hall_flags = IQS620_HALL_FLAGS,
.clk_div = 4,
.fw_name = "iqs620a.bin",
.event_regs = &iqs620a_event_regs[IQS62X_UI_PROX],
},
......@@ -796,23 +830,18 @@ static const struct iqs62x_dev_desc iqs62x_devs[] = {
.dev_name = "iqs621",
.sub_devs = iqs621_sub_devs,
.num_sub_devs = ARRAY_SIZE(iqs621_sub_devs),
.prod_num = IQS621_PROD_NUM,
.sw_num = 0x09,
.cal_regs = iqs621_cal_regs,
.num_cal_regs = ARRAY_SIZE(iqs621_cal_regs),
.prox_mask = BIT(0),
.hall_mask = BIT(1),
.als_mask = BIT(2),
.hyst_mask = BIT(3),
.temp_mask = BIT(4),
.als_flags = IQS621_ALS_FLAGS,
.hall_flags = IQS621_HALL_FLAGS,
.hyst_shift = 5,
.clk_div = 2,
.fw_name = "iqs621.bin",
.event_regs = &iqs621_event_regs[IQS62X_UI_PROX],
},
......@@ -820,21 +849,16 @@ static const struct iqs62x_dev_desc iqs62x_devs[] = {
.dev_name = "iqs622",
.sub_devs = iqs622_sub_devs,
.num_sub_devs = ARRAY_SIZE(iqs622_sub_devs),
.prod_num = IQS622_PROD_NUM,
.sw_num = 0x06,
.prox_mask = BIT(0),
.sar_mask = BIT(1),
.hall_mask = BIT(2),
.als_mask = BIT(3),
.ir_mask = BIT(4),
.prox_settings = IQS622_PROX_SETTINGS_4,
.als_flags = IQS622_ALS_FLAGS,
.hall_flags = IQS622_HALL_FLAGS,
.clk_div = 2,
.fw_name = "iqs622.bin",
.event_regs = &iqs622_event_regs[IQS62X_UI_PROX],
},
......@@ -842,14 +866,10 @@ static const struct iqs62x_dev_desc iqs62x_devs[] = {
.dev_name = "iqs624",
.sub_devs = iqs624_sub_devs,
.num_sub_devs = ARRAY_SIZE(iqs624_sub_devs),
.prod_num = IQS624_PROD_NUM,
.sw_num = 0x0B,
.interval = IQS624_INTERVAL_NUM,
.interval_div = 3,
.clk_div = 2,
.fw_name = "iqs624.bin",
.event_regs = &iqs624_event_regs[IQS62X_UI_PROX],
},
......@@ -857,20 +877,16 @@ static const struct iqs62x_dev_desc iqs62x_devs[] = {
.dev_name = "iqs625",
.sub_devs = iqs625_sub_devs,
.num_sub_devs = ARRAY_SIZE(iqs625_sub_devs),
.prod_num = IQS625_PROD_NUM,
.sw_num = 0x0B,
.interval = IQS625_INTERVAL_NUM,
.interval_div = 10,
.clk_div = 2,
.fw_name = "iqs625.bin",
.event_regs = &iqs625_event_regs[IQS62X_UI_PROX],
},
};
static const struct regmap_config iqs62x_map_config = {
static const struct regmap_config iqs62x_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = IQS62X_MAX_REG,
......@@ -894,9 +910,11 @@ static int iqs62x_probe(struct i2c_client *client)
BLOCKING_INIT_NOTIFIER_HEAD(&iqs62x->nh);
INIT_LIST_HEAD(&iqs62x->fw_blk_head);
init_completion(&iqs62x->ati_done);
init_completion(&iqs62x->fw_done);
iqs62x->regmap = devm_regmap_init_i2c(client, &iqs62x_map_config);
iqs62x->regmap = devm_regmap_init_i2c(client, &iqs62x_regmap_config);
if (IS_ERR(iqs62x->regmap)) {
ret = PTR_ERR(iqs62x->regmap);
dev_err(&client->dev, "Failed to initialize register map: %d\n",
......
......@@ -29,9 +29,9 @@
static const struct mfd_cell max8997_devs[] = {
{ .name = "max8997-pmic", },
{ .name = "max8997-rtc", },
{ .name = "max8997-battery", },
{ .name = "max8997-battery", .of_compatible = "maxim,max8997-battery", },
{ .name = "max8997-haptic", },
{ .name = "max8997-muic", },
{ .name = "max8997-muic", .of_compatible = "maxim,max8997-muic", },
{ .name = "max8997-led", .id = 1 },
{ .name = "max8997-led", .id = 2 },
};
......
......@@ -214,8 +214,7 @@ static int mcp_sa11x0_probe(struct platform_device *dev)
* rate. This is the period for 3 64-bit frames. Always
* round this time up.
*/
mcp->rw_timeout = (64 * 3 * 1000000 + mcp->sclk_rate - 1) /
mcp->sclk_rate;
mcp->rw_timeout = DIV_ROUND_UP(64 * 3 * 1000000, mcp->sclk_rate);
ret = mcp_host_add(mcp, data->codec_pdata);
if (ret == 0)
......
......@@ -292,17 +292,17 @@ static const struct resource mt6360_ldo_resources[] = {
};
static const struct mfd_cell mt6360_devs[] = {
OF_MFD_CELL("mt6360_adc", mt6360_adc_resources,
MFD_CELL_OF("mt6360_adc", mt6360_adc_resources,
NULL, 0, 0, "mediatek,mt6360_adc"),
OF_MFD_CELL("mt6360_chg", mt6360_chg_resources,
MFD_CELL_OF("mt6360_chg", mt6360_chg_resources,
NULL, 0, 0, "mediatek,mt6360_chg"),
OF_MFD_CELL("mt6360_led", mt6360_led_resources,
MFD_CELL_OF("mt6360_led", mt6360_led_resources,
NULL, 0, 0, "mediatek,mt6360_led"),
OF_MFD_CELL("mt6360_pmic", mt6360_pmic_resources,
MFD_CELL_OF("mt6360_pmic", mt6360_pmic_resources,
NULL, 0, 0, "mediatek,mt6360_pmic"),
OF_MFD_CELL("mt6360_ldo", mt6360_ldo_resources,
MFD_CELL_OF("mt6360_ldo", mt6360_ldo_resources,
NULL, 0, 0, "mediatek,mt6360_ldo"),
OF_MFD_CELL("mt6360_tcpc", NULL,
MFD_CELL_OF("mt6360_tcpc", NULL,
NULL, 0, 0, "mediatek,mt6360_tcpc"),
};
......
......@@ -93,11 +93,10 @@ static int wm831x_auxadc_read_irq(struct wm831x *wm831x,
wait_for_completion_timeout(&req->done, msecs_to_jiffies(500));
mutex_lock(&wm831x->auxadc_lock);
list_del(&req->list);
ret = req->val;
out:
list_del(&req->list);
mutex_unlock(&wm831x->auxadc_lock);
kfree(req);
......
// SPDX-License-Identifier: GPL-2.0
/*
* ROHM BD9571MWV-M regulator driver
* ROHM BD9571MWV-M and BD9574MWF-M regulator driver
*
* Copyright (C) 2017 Marek Vasut <marek.vasut+renesas@gmail.com>
*
......@@ -9,6 +9,7 @@
* NOTE: VD09 is missing
*/
#include <linux/mfd/rohm-generic.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
......@@ -17,7 +18,7 @@
#include <linux/mfd/bd9571mwv.h>
struct bd9571mwv_reg {
struct bd9571mwv *bd;
struct regmap *regmap;
/* DDR Backup Power */
u8 bkup_mode_cnt_keepon; /* from "rohm,ddr-backup-power" */
......@@ -137,26 +138,30 @@ static const struct regulator_desc regulators[] = {
};
#ifdef CONFIG_PM_SLEEP
static int bd9571mwv_bkup_mode_read(struct bd9571mwv *bd, unsigned int *mode)
static int bd9571mwv_bkup_mode_read(struct bd9571mwv_reg *bdreg,
unsigned int *mode)
{
int ret;
ret = regmap_read(bd->regmap, BD9571MWV_BKUP_MODE_CNT, mode);
ret = regmap_read(bdreg->regmap, BD9571MWV_BKUP_MODE_CNT, mode);
if (ret) {
dev_err(bd->dev, "failed to read backup mode (%d)\n", ret);
dev_err(regmap_get_device(bdreg->regmap),
"failed to read backup mode (%d)\n", ret);
return ret;
}
return 0;
}
static int bd9571mwv_bkup_mode_write(struct bd9571mwv *bd, unsigned int mode)
static int bd9571mwv_bkup_mode_write(struct bd9571mwv_reg *bdreg,
unsigned int mode)
{
int ret;
ret = regmap_write(bd->regmap, BD9571MWV_BKUP_MODE_CNT, mode);
ret = regmap_write(bdreg->regmap, BD9571MWV_BKUP_MODE_CNT, mode);
if (ret) {
dev_err(bd->dev, "failed to configure backup mode 0x%x (%d)\n",
dev_err(regmap_get_device(bdreg->regmap),
"failed to configure backup mode 0x%x (%d)\n",
mode, ret);
return ret;
}
......@@ -194,7 +199,7 @@ static ssize_t backup_mode_store(struct device *dev,
* Configure DDR Backup Mode, to change the role of the accessory power
* switch from a power switch to a wake-up switch, or vice versa
*/
ret = bd9571mwv_bkup_mode_read(bdreg->bd, &mode);
ret = bd9571mwv_bkup_mode_read(bdreg, &mode);
if (ret)
return ret;
......@@ -202,7 +207,7 @@ static ssize_t backup_mode_store(struct device *dev,
if (bdreg->bkup_mode_enabled)
mode |= bdreg->bkup_mode_cnt_keepon;
ret = bd9571mwv_bkup_mode_write(bdreg->bd, mode);
ret = bd9571mwv_bkup_mode_write(bdreg, mode);
if (ret)
return ret;
......@@ -221,7 +226,7 @@ static int bd9571mwv_suspend(struct device *dev)
return 0;
/* Save DDR Backup Mode */
ret = bd9571mwv_bkup_mode_read(bdreg->bd, &mode);
ret = bd9571mwv_bkup_mode_read(bdreg, &mode);
if (ret)
return ret;
......@@ -235,7 +240,7 @@ static int bd9571mwv_suspend(struct device *dev)
mode |= bdreg->bkup_mode_cnt_keepon;
if (mode != bdreg->bkup_mode_cnt_saved)
return bd9571mwv_bkup_mode_write(bdreg->bd, mode);
return bd9571mwv_bkup_mode_write(bdreg, mode);
return 0;
}
......@@ -248,7 +253,7 @@ static int bd9571mwv_resume(struct device *dev)
return 0;
/* Restore DDR Backup Mode */
return bd9571mwv_bkup_mode_write(bdreg->bd, bdreg->bkup_mode_cnt_saved);
return bd9571mwv_bkup_mode_write(bdreg, bdreg->bkup_mode_cnt_saved);
}
static const struct dev_pm_ops bd9571mwv_pm = {
......@@ -268,51 +273,54 @@ static int bd9571mwv_regulator_remove(struct platform_device *pdev)
static int bd9571mwv_regulator_probe(struct platform_device *pdev)
{
struct bd9571mwv *bd = dev_get_drvdata(pdev->dev.parent);
struct regulator_config config = { };
struct bd9571mwv_reg *bdreg;
struct regulator_dev *rdev;
unsigned int val;
int i;
enum rohm_chip_type chip = platform_get_device_id(pdev)->driver_data;
bdreg = devm_kzalloc(&pdev->dev, sizeof(*bdreg), GFP_KERNEL);
if (!bdreg)
return -ENOMEM;
bdreg->bd = bd;
bdreg->regmap = dev_get_regmap(pdev->dev.parent, NULL);
platform_set_drvdata(pdev, bdreg);
config.dev = &pdev->dev;
config.dev->of_node = bd->dev->of_node;
config.driver_data = bd;
config.regmap = bd->regmap;
config.dev->of_node = pdev->dev.parent->of_node;
config.driver_data = bdreg;
config.regmap = bdreg->regmap;
for (i = 0; i < ARRAY_SIZE(regulators); i++) {
/* BD9574MWF supports DVFS only */
if (chip == ROHM_CHIP_TYPE_BD9574 && regulators[i].id != DVFS)
continue;
rdev = devm_regulator_register(&pdev->dev, &regulators[i],
&config);
if (IS_ERR(rdev)) {
dev_err(bd->dev, "failed to register %s regulator\n",
dev_err(&pdev->dev, "failed to register %s regulator\n",
pdev->name);
return PTR_ERR(rdev);
}
}
val = 0;
of_property_read_u32(bd->dev->of_node, "rohm,ddr-backup-power", &val);
of_property_read_u32(config.dev->of_node, "rohm,ddr-backup-power", &val);
if (val & ~BD9571MWV_BKUP_MODE_CNT_KEEPON_MASK) {
dev_err(bd->dev, "invalid %s mode %u\n",
dev_err(&pdev->dev, "invalid %s mode %u\n",
"rohm,ddr-backup-power", val);
return -EINVAL;
}
bdreg->bkup_mode_cnt_keepon = val;
bdreg->rstbmode_level = of_property_read_bool(bd->dev->of_node,
bdreg->rstbmode_level = of_property_read_bool(config.dev->of_node,
"rohm,rstbmode-level");
bdreg->rstbmode_pulse = of_property_read_bool(bd->dev->of_node,
bdreg->rstbmode_pulse = of_property_read_bool(config.dev->of_node,
"rohm,rstbmode-pulse");
if (bdreg->rstbmode_level && bdreg->rstbmode_pulse) {
dev_err(bd->dev, "only one rohm,rstbmode-* may be specified");
dev_err(&pdev->dev, "only one rohm,rstbmode-* may be specified");
return -EINVAL;
}
......@@ -336,7 +344,8 @@ static int bd9571mwv_regulator_probe(struct platform_device *pdev)
}
static const struct platform_device_id bd9571mwv_regulator_id_table[] = {
{ "bd9571mwv-regulator", },
{ "bd9571mwv-regulator", ROHM_CHIP_TYPE_BD9571 },
{ "bd9574mwf-regulator", ROHM_CHIP_TYPE_BD9574 },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(platform, bd9571mwv_regulator_id_table);
......
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* ROHM BD9571MWV-M driver
* ROHM BD9571MWV-M and BD9574MWF-M driver
*
* Copyright (C) 2017 Marek Vasut <marek.vasut+renesas@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
* kind, whether expressed or implied; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License version 2 for more details.
* Copyright (C) 2020 Renesas Electronics Corporation
*
* Based on the TPS65086 driver
*/
......@@ -21,11 +14,12 @@
#include <linux/device.h>
#include <linux/regmap.h>
/* List of registers for BD9571MWV */
/* List of registers for BD9571MWV and BD9574MWF */
#define BD9571MWV_VENDOR_CODE 0x00
#define BD9571MWV_VENDOR_CODE_VAL 0xdb
#define BD9571MWV_PRODUCT_CODE 0x01
#define BD9571MWV_PRODUCT_CODE_VAL 0x60
#define BD9571MWV_PRODUCT_CODE_BD9571MWV 0x60
#define BD9571MWV_PRODUCT_CODE_BD9574MWF 0x74
#define BD9571MWV_PRODUCT_REVISION 0x02
#define BD9571MWV_I2C_FUSA_MODE 0x10
......@@ -55,6 +49,7 @@
#define BD9571MWV_VD33_VID 0x44
#define BD9571MWV_DVFS_VINIT 0x50
#define BD9574MWF_VD09_VINIT 0x51
#define BD9571MWV_DVFS_SETVMAX 0x52
#define BD9571MWV_DVFS_BOOSTVID 0x53
#define BD9571MWV_DVFS_SETVID 0x54
......@@ -68,6 +63,7 @@
#define BD9571MWV_GPIO_INT_SET 0x64
#define BD9571MWV_GPIO_INT 0x65
#define BD9571MWV_GPIO_INTMASK 0x66
#define BD9574MWF_GPIO_MUX 0x67
#define BD9571MWV_REG_KEEP(n) (0x70 + (n))
......@@ -77,6 +73,8 @@
#define BD9571MWV_PROT_ERROR_STATUS2 0x83
#define BD9571MWV_PROT_ERROR_STATUS3 0x84
#define BD9571MWV_PROT_ERROR_STATUS4 0x85
#define BD9574MWF_PROT_ERROR_STATUS5 0x86
#define BD9574MWF_SYSTEM_ERROR_STATUS 0x87
#define BD9571MWV_INT_INTREQ 0x90
#define BD9571MWV_INT_INTREQ_MD1_INT BIT(0)
......@@ -89,6 +87,12 @@
#define BD9571MWV_INT_INTREQ_BKUP_TRG_INT BIT(7)
#define BD9571MWV_INT_INTMASK 0x91
#define BD9574MWF_SSCG_CNT 0xA0
#define BD9574MWF_POFFB_MRB 0xA1
#define BD9574MWF_SMRB_WR_PROT 0xA2
#define BD9574MWF_SMRB_ASSERT 0xA3
#define BD9574MWF_SMRB_STATUS 0xA4
#define BD9571MWV_ACCESS_KEY 0xff
/* Define the BD9571MWV IRQ numbers */
......@@ -98,23 +102,8 @@ enum bd9571mwv_irqs {
BD9571MWV_IRQ_MD2_E2,
BD9571MWV_IRQ_PROT_ERR,
BD9571MWV_IRQ_GP,
BD9571MWV_IRQ_128H_OF,
BD9571MWV_IRQ_128H_OF, /* BKUP_HOLD on BD9574MWF */
BD9571MWV_IRQ_WDT_OF,
BD9571MWV_IRQ_BKUP_TRG,
};
/**
* struct bd9571mwv - state holder for the bd9571mwv driver
*
* Device data may be used to access the BD9571MWV chip
*/
struct bd9571mwv {
struct device *dev;
struct regmap *regmap;
/* IRQ Data */
int irq;
struct regmap_irq_chip_data *irq_data;
};
#endif /* __LINUX_MFD_BD9571MWV_H */
......@@ -28,13 +28,13 @@
.id = (_id), \
}
#define OF_MFD_CELL_REG(_name, _res, _pdata, _pdsize, _id, _compat, _of_reg) \
#define MFD_CELL_OF_REG(_name, _res, _pdata, _pdsize, _id, _compat, _of_reg) \
MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, _compat, _of_reg, true, NULL)
#define OF_MFD_CELL(_name, _res, _pdata, _pdsize, _id, _compat) \
#define MFD_CELL_OF(_name, _res, _pdata, _pdsize, _id, _compat) \
MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, _compat, 0, false, NULL)
#define ACPI_MFD_CELL(_name, _res, _pdata, _pdsize, _id, _match) \
#define MFD_CELL_ACPI(_name, _res, _pdata, _pdsize, _id, _match) \
MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, NULL, 0, false, _match)
#define MFD_CELL_BASIC(_name, _res, _pdata, _pdsize, _id) \
......
......@@ -15,6 +15,15 @@
/* Register offset of system registers */
#define NIOS2_FW_VERSION 0x0
#define M10BMC_MAC_LOW 0x10
#define M10BMC_MAC_BYTE4 GENMASK(7, 0)
#define M10BMC_MAC_BYTE3 GENMASK(15, 8)
#define M10BMC_MAC_BYTE2 GENMASK(23, 16)
#define M10BMC_MAC_BYTE1 GENMASK(31, 24)
#define M10BMC_MAC_HIGH 0x14
#define M10BMC_MAC_BYTE6 GENMASK(7, 0)
#define M10BMC_MAC_BYTE5 GENMASK(15, 8)
#define M10BMC_MAC_COUNT GENMASK(23, 16)
#define M10BMC_TEST_REG 0x3c
#define M10BMC_BUILD_VER 0x68
#define M10BMC_VER_MAJOR_MSK GENMASK(23, 16)
......
......@@ -28,7 +28,7 @@
#define IQS620_GLBL_EVENT_MASK_PMU BIT(6)
#define IQS62X_NUM_KEYS 16
#define IQS62X_NUM_EVENTS (IQS62X_NUM_KEYS + 5)
#define IQS62X_NUM_EVENTS (IQS62X_NUM_KEYS + 6)
#define IQS62X_EVENT_SIZE 10
......@@ -78,6 +78,7 @@ enum iqs62x_event_flag {
/* everything else */
IQS62X_EVENT_SYS_RESET,
IQS62X_EVENT_SYS_ATI,
};
struct iqs62x_event_data {
......@@ -97,12 +98,10 @@ struct iqs62x_dev_desc {
const char *dev_name;
const struct mfd_cell *sub_devs;
int num_sub_devs;
u8 prod_num;
u8 sw_num;
const u8 *cal_regs;
int num_cal_regs;
u8 prox_mask;
u8 sar_mask;
u8 hall_mask;
......@@ -110,16 +109,12 @@ struct iqs62x_dev_desc {
u8 temp_mask;
u8 als_mask;
u8 ir_mask;
u8 prox_settings;
u8 als_flags;
u8 hall_flags;
u8 hyst_shift;
u8 interval;
u8 interval_div;
u8 clk_div;
const char *fw_name;
const enum iqs62x_event_reg (*event_regs)[IQS62X_EVENT_SIZE];
};
......@@ -130,8 +125,10 @@ struct iqs62x_core {
struct regmap *regmap;
struct blocking_notifier_head nh;
struct list_head fw_blk_head;
struct completion ati_done;
struct completion fw_done;
enum iqs62x_ui_sel ui_sel;
unsigned long event_cache;
};
extern const struct iqs62x_event_desc iqs62x_events[IQS62X_NUM_EVENTS];
......
......@@ -12,6 +12,8 @@ enum rohm_chip_type {
ROHM_CHIP_TYPE_BD71847,
ROHM_CHIP_TYPE_BD70528,
ROHM_CHIP_TYPE_BD71828,
ROHM_CHIP_TYPE_BD9571,
ROHM_CHIP_TYPE_BD9574,
ROHM_CHIP_TYPE_AMOUNT
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment