Commit e8a6f4ac authored by Lee Jones's avatar Lee Jones

Merge branches 'ib-mfd-x86-usb-watchdog-5.8', 'ib-mfd-power-rtc-5.8',...

Merge branches 'ib-mfd-x86-usb-watchdog-5.8', 'ib-mfd-power-rtc-5.8', 'ib-mfd-iio-power-5.8' and 'ib-mfd-hwmon-5.8' into ibs-for-mfd-merged
What: /sys/class/power_supply/mp2629_battery/batt_impedance_compen
Date: April 2020
KernelVersion: 5.7
Description:
Represents a battery impedance compensation to accelerate charging.
Access: Read, Write
Valid values: Represented in milli-ohms. Valid range is [0, 140].
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/mfd/gateworks-gsc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Gateworks System Controller
description: |
The Gateworks System Controller (GSC) is a device present across various
Gateworks product families that provides a set of system related features
such as the following (refer to the board hardware user manuals to see what
features are present)
- Watchdog Timer
- GPIO
- Pushbutton controller
- Hardware monitor with ADC's for temperature and voltage rails and
fan controller
maintainers:
- Tim Harvey <tharvey@gateworks.com>
- Robert Jones <rjones@gateworks.com>
properties:
$nodename:
pattern: "gsc@[0-9a-f]{1,2}"
compatible:
const: gw,gsc
reg:
description: I2C device address
maxItems: 1
interrupts:
maxItems: 1
interrupt-controller: true
"#interrupt-cells":
const: 1
"#address-cells":
const: 1
"#size-cells":
const: 0
adc:
type: object
description: Optional hardware monitoring module
properties:
compatible:
const: gw,gsc-adc
"#address-cells":
const: 1
"#size-cells":
const: 0
patternProperties:
"^channel@[0-9]+$":
type: object
description: |
Properties for a single ADC which can report cooked values
(i.e. temperature sensor based on thermister), raw values
(i.e. voltage rail with a pre-scaling resistor divider).
properties:
reg:
description: Register of the ADC
maxItems: 1
label:
description: Name of the ADC input
gw,mode:
description: |
conversion mode:
0 - temperature, in C*10
1 - pre-scaled voltage value
2 - scaled voltage based on an optional resistor divider
and optional offset
$ref: /schemas/types.yaml#/definitions/uint32
enum: [0, 1, 2]
gw,voltage-divider-ohms:
description: Values of resistors for divider on raw ADC input
maxItems: 2
items:
minimum: 1000
maximum: 1000000
gw,voltage-offset-microvolt:
description: |
A positive voltage offset to apply to a raw ADC
(i.e. to compensate for a diode drop).
minimum: 0
maximum: 1000000
required:
- gw,mode
- reg
- label
required:
- compatible
- "#address-cells"
- "#size-cells"
patternProperties:
"^fan-controller@[0-9a-f]+$":
type: object
description: Optional fan controller
properties:
compatible:
const: gw,gsc-fan
"#address-cells":
const: 1
"#size-cells":
const: 0
reg:
description: The fan controller base address
maxItems: 1
required:
- compatible
- reg
- "#address-cells"
- "#size-cells"
required:
- compatible
- reg
- interrupts
- interrupt-controller
- "#interrupt-cells"
- "#address-cells"
- "#size-cells"
examples:
- |
#include <dt-bindings/gpio/gpio.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
gsc@20 {
compatible = "gw,gsc";
reg = <0x20>;
interrupt-parent = <&gpio1>;
interrupts = <4 GPIO_ACTIVE_LOW>;
interrupt-controller;
#interrupt-cells = <1>;
#address-cells = <1>;
#size-cells = <0>;
adc {
compatible = "gw,gsc-adc";
#address-cells = <1>;
#size-cells = <0>;
channel@0 { /* A0: Board Temperature */
reg = <0x00>;
label = "temp";
gw,mode = <0>;
};
channel@2 { /* A1: Input Voltage (raw ADC) */
reg = <0x02>;
label = "vdd_vin";
gw,mode = <1>;
gw,voltage-divider-ohms = <22100 1000>;
gw,voltage-offset-microvolt = <800000>;
};
channel@b { /* A2: Battery voltage */
reg = <0x0b>;
label = "vdd_bat";
gw,mode = <1>;
};
};
fan-controller@2c {
#address-cells = <1>;
#size-cells = <0>;
compatible = "gw,gsc-fan";
reg = <0x2c>;
};
};
};
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/mfd/mps,mp2629.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: MP2629 Battery Charger PMIC from Monolithic Power System.
maintainers:
- Saravanan Sekar <sravanhome@gmail.com>
description: |
MP2629 is a PMIC providing battery charging and power supply for smartphones,
wireless camera and portable devices. Chip is controlled over I2C.
The battery charge management device handles battery charger controller and
ADC IIO device for battery, system voltage
properties:
compatible:
const: mps,mp2629
reg:
maxItems: 1
interrupts:
maxItems: 1
interrupt-controller: true
"#interrupt-cells":
const: 2
description:
The first cell is the IRQ number, the second cell is the trigger type.
required:
- compatible
- reg
- interrupts
- interrupt-controller
- "#interrupt-cells"
additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/input/linux-event-codes.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
pmic@4b {
compatible = "mps,mp2629";
reg = <0x4b>;
interrupt-controller;
interrupt-parent = <&gpio2>;
#interrupt-cells = <2>;
interrupts = <3 IRQ_TYPE_LEVEL_HIGH>;
};
};
...@@ -18,24 +18,30 @@ See the following for pwarp node definitions: ...@@ -18,24 +18,30 @@ See the following for pwarp node definitions:
This document describes the binding for MFD device and its sub module. This document describes the binding for MFD device and its sub module.
Required properties: Required properties:
compatible: "mediatek,mt6397" or "mediatek,mt6323" compatible:
"mediatek,mt6323" for PMIC MT6323
"mediatek,mt6358" for PMIC MT6358
"mediatek,mt6397" for PMIC MT6397
Optional subnodes: Optional subnodes:
- rtc - rtc
Required properties: Should be one of follows Required properties: Should be one of follows
- compatible: "mediatek,mt6323-rtc" - compatible: "mediatek,mt6323-rtc"
- compatible: "mediatek,mt6358-rtc"
- compatible: "mediatek,mt6397-rtc" - compatible: "mediatek,mt6397-rtc"
For details, see ../rtc/rtc-mt6397.txt For details, see ../rtc/rtc-mt6397.txt
- regulators - regulators
Required properties: Required properties:
- compatible: "mediatek,mt6397-regulator"
see ../regulator/mt6397-regulator.txt
- compatible: "mediatek,mt6323-regulator" - compatible: "mediatek,mt6323-regulator"
see ../regulator/mt6323-regulator.txt see ../regulator/mt6323-regulator.txt
- compatible: "mediatek,mt6358-regulator"
see ../regulator/mt6358-regulator.txt
- compatible: "mediatek,mt6397-regulator"
see ../regulator/mt6397-regulator.txt
- codec - codec
Required properties: Required properties:
- compatible: "mediatek,mt6397-codec" - compatible: "mediatek,mt6397-codec" or "mediatek,mt6358-sound"
- clk - clk
Required properties: Required properties:
- compatible: "mediatek,mt6397-clk" - compatible: "mediatek,mt6397-clk"
......
.. SPDX-License-Identifier: GPL-2.0
Kernel driver gsc-hwmon
=======================
Supported chips: Gateworks GSC
Datasheet: http://trac.gateworks.com/wiki/gsc
Author: Tim Harvey <tharvey@gateworks.com>
Description:
------------
This driver supports hardware monitoring for the temperature sensor,
various ADC's connected to the GSC, and optional FAN controller available
on some boards.
Voltage Monitoring
------------------
The voltage inputs are scaled either internally or by the driver depending
on the GSC version and firmware. The values returned by the driver do not need
further scaling. The voltage input labels provide the voltage rail name:
inX_input Measured voltage (mV).
inX_label Name of voltage rail.
Temperature Monitoring
----------------------
Temperatures are measured with 12-bit or 10-bit resolution and are scaled
either internally or by the driver depending on the GSC version and firmware.
The values returned by the driver reflect millidegree Celcius:
tempX_input Measured temperature.
tempX_label Name of temperature input.
PWM Output Control
------------------
The GSC features 1 PWM output that operates in automatic mode where the
PWM value will be scalled depending on 6 temperature boundaries.
The tempeature boundaries are read-write and in millidegree Celcius and the
read-only PWM values range from 0 (off) to 255 (full speed).
Fan speed will be set to minimum (off) when the temperature sensor reads
less than pwm1_auto_point1_temp and maximum when the temperature sensor
equals or exceeds pwm1_auto_point6_temp.
pwm1_auto_point[1-6]_pwm PWM value.
pwm1_auto_point[1-6]_temp Temperature boundary.
...@@ -60,6 +60,7 @@ Hardware Monitoring Kernel Drivers ...@@ -60,6 +60,7 @@ Hardware Monitoring Kernel Drivers
ftsteutates ftsteutates
g760a g760a
g762 g762
gsc-hwmon
gl518sm gl518sm
hih6130 hih6130
ibmaem ibmaem
......
...@@ -7028,6 +7028,17 @@ F: kernel/futex.c ...@@ -7028,6 +7028,17 @@ F: kernel/futex.c
F: tools/perf/bench/futex* F: tools/perf/bench/futex*
F: tools/testing/selftests/futex/ F: tools/testing/selftests/futex/
GATEWORKS SYSTEM CONTROLLER (GSC) DRIVER
M: Tim Harvey <tharvey@gateworks.com>
M: Robert Jones <rjones@gateworks.com>
S: Maintained
F: Documentation/devicetree/bindings/mfd/gateworks-gsc.yaml
F: drivers/mfd/gateworks-gsc.c
F: include/linux/mfd/gsc.h
F: Documentation/hwmon/gsc-hwmon.rst
F: drivers/hwmon/gsc-hwmon.c
F: include/linux/platform_data/gsc_hwmon.h
GASKET DRIVER FRAMEWORK GASKET DRIVER FRAMEWORK
M: Rob Springer <rspringer@google.com> M: Rob Springer <rspringer@google.com>
M: Todd Poynor <toddpoynor@google.com> M: Todd Poynor <toddpoynor@google.com>
...@@ -11382,10 +11393,15 @@ F: kernel/module.c ...@@ -11382,10 +11393,15 @@ F: kernel/module.c
MONOLITHIC POWER SYSTEM PMIC DRIVER MONOLITHIC POWER SYSTEM PMIC DRIVER
M: Saravanan Sekar <sravanhome@gmail.com> M: Saravanan Sekar <sravanhome@gmail.com>
S: Maintained S: Maintained
F: Documentation/devicetree/bindings/mfd/mps,mp2629.yaml
F: Documentation/devicetree/bindings/regulator/mps,mp*.yaml F: Documentation/devicetree/bindings/regulator/mps,mp*.yaml
F: drivers/iio/adc/mp2629_adc.c
F: drivers/mfd/mp2629.c
F: drivers/power/supply/mp2629_charger.c
F: drivers/regulator/mp5416.c F: drivers/regulator/mp5416.c
F: drivers/regulator/mpq7920.c F: drivers/regulator/mpq7920.c
F: drivers/regulator/mpq7920.h F: drivers/regulator/mpq7920.h
F: include/linux/mfd/mp2629.h
MOTION EYE VAIO PICTUREBOOK CAMERA DRIVER MOTION EYE VAIO PICTUREBOOK CAMERA DRIVER
S: Orphan S: Orphan
......
...@@ -523,6 +523,15 @@ config SENSORS_F75375S ...@@ -523,6 +523,15 @@ config SENSORS_F75375S
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 f75375s. will be called f75375s.
config SENSORS_GSC
tristate "Gateworks System Controller ADC"
depends on MFD_GATEWORKS_GSC
help
Support for the Gateworks System Controller A/D converters.
To compile this driver as a module, choose M here:
the module will be called gsc-hwmon.
config SENSORS_MC13783_ADC config SENSORS_MC13783_ADC
tristate "Freescale MC13783/MC13892 ADC" tristate "Freescale MC13783/MC13892 ADC"
depends on MFD_MC13XXX depends on MFD_MC13XXX
......
...@@ -74,6 +74,7 @@ obj-$(CONFIG_SENSORS_G760A) += g760a.o ...@@ -74,6 +74,7 @@ obj-$(CONFIG_SENSORS_G760A) += g760a.o
obj-$(CONFIG_SENSORS_G762) += g762.o obj-$(CONFIG_SENSORS_G762) += g762.o
obj-$(CONFIG_SENSORS_GL518SM) += gl518sm.o obj-$(CONFIG_SENSORS_GL518SM) += gl518sm.o
obj-$(CONFIG_SENSORS_GL520SM) += gl520sm.o obj-$(CONFIG_SENSORS_GL520SM) += gl520sm.o
obj-$(CONFIG_SENSORS_GSC) += gsc-hwmon.o
obj-$(CONFIG_SENSORS_GPIO_FAN) += gpio-fan.o obj-$(CONFIG_SENSORS_GPIO_FAN) += gpio-fan.o
obj-$(CONFIG_SENSORS_HIH6130) += hih6130.o obj-$(CONFIG_SENSORS_HIH6130) += hih6130.o
obj-$(CONFIG_SENSORS_ULTRA45) += ultra45_env.o obj-$(CONFIG_SENSORS_ULTRA45) += ultra45_env.o
......
// SPDX-License-Identifier: GPL-2.0
/*
* Driver for Gateworks System Controller Hardware Monitor module
*
* Copyright (C) 2020 Gateworks Corporation
*/
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/mfd/gsc.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/platform_data/gsc_hwmon.h>
#define GSC_HWMON_MAX_TEMP_CH 16
#define GSC_HWMON_MAX_IN_CH 16
#define GSC_HWMON_RESOLUTION 12
#define GSC_HWMON_VREF 2500
struct gsc_hwmon_data {
struct gsc_dev *gsc;
struct gsc_hwmon_platform_data *pdata;
struct regmap *regmap;
const struct gsc_hwmon_channel *temp_ch[GSC_HWMON_MAX_TEMP_CH];
const struct gsc_hwmon_channel *in_ch[GSC_HWMON_MAX_IN_CH];
u32 temp_config[GSC_HWMON_MAX_TEMP_CH + 1];
u32 in_config[GSC_HWMON_MAX_IN_CH + 1];
struct hwmon_channel_info temp_info;
struct hwmon_channel_info in_info;
const struct hwmon_channel_info *info[3];
struct hwmon_chip_info chip;
};
static struct regmap_bus gsc_hwmon_regmap_bus = {
.reg_read = gsc_read,
.reg_write = gsc_write,
};
static const struct regmap_config gsc_hwmon_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.cache_type = REGCACHE_NONE,
};
static ssize_t pwm_auto_point_temp_show(struct device *dev,
struct device_attribute *devattr,
char *buf)
{
struct gsc_hwmon_data *hwmon = dev_get_drvdata(dev);
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
u8 reg = hwmon->pdata->fan_base + (2 * attr->index);
u8 regs[2];
int ret;
ret = regmap_bulk_read(hwmon->regmap, reg, regs, 2);
if (ret)
return ret;
ret = regs[0] | regs[1] << 8;
return sprintf(buf, "%d\n", ret * 10);
}
static ssize_t pwm_auto_point_temp_store(struct device *dev,
struct device_attribute *devattr,
const char *buf, size_t count)
{
struct gsc_hwmon_data *hwmon = dev_get_drvdata(dev);
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
u8 reg = hwmon->pdata->fan_base + (2 * attr->index);
u8 regs[2];
long temp;
int err;
if (kstrtol(buf, 10, &temp))
return -EINVAL;
temp = clamp_val(temp, 0, 10000);
temp = DIV_ROUND_CLOSEST(temp, 10);
regs[0] = temp & 0xff;
regs[1] = (temp >> 8) & 0xff;
err = regmap_bulk_write(hwmon->regmap, reg, regs, 2);
if (err)
return err;
return count;
}
static ssize_t pwm_auto_point_pwm_show(struct device *dev,
struct device_attribute *devattr,
char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
return sprintf(buf, "%d\n", 255 * (50 + (attr->index * 10)) / 100);
}
static SENSOR_DEVICE_ATTR_RO(pwm1_auto_point1_pwm, pwm_auto_point_pwm, 0);
static SENSOR_DEVICE_ATTR_RW(pwm1_auto_point1_temp, pwm_auto_point_temp, 0);
static SENSOR_DEVICE_ATTR_RO(pwm1_auto_point2_pwm, pwm_auto_point_pwm, 1);
static SENSOR_DEVICE_ATTR_RW(pwm1_auto_point2_temp, pwm_auto_point_temp, 1);
static SENSOR_DEVICE_ATTR_RO(pwm1_auto_point3_pwm, pwm_auto_point_pwm, 2);
static SENSOR_DEVICE_ATTR_RW(pwm1_auto_point3_temp, pwm_auto_point_temp, 2);
static SENSOR_DEVICE_ATTR_RO(pwm1_auto_point4_pwm, pwm_auto_point_pwm, 3);
static SENSOR_DEVICE_ATTR_RW(pwm1_auto_point4_temp, pwm_auto_point_temp, 3);
static SENSOR_DEVICE_ATTR_RO(pwm1_auto_point5_pwm, pwm_auto_point_pwm, 4);
static SENSOR_DEVICE_ATTR_RW(pwm1_auto_point5_temp, pwm_auto_point_temp, 4);
static SENSOR_DEVICE_ATTR_RO(pwm1_auto_point6_pwm, pwm_auto_point_pwm, 5);
static SENSOR_DEVICE_ATTR_RW(pwm1_auto_point6_temp, pwm_auto_point_temp, 5);
static struct attribute *gsc_hwmon_attributes[] = {
&sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr,
&sensor_dev_attr_pwm1_auto_point1_temp.dev_attr.attr,
&sensor_dev_attr_pwm1_auto_point2_pwm.dev_attr.attr,
&sensor_dev_attr_pwm1_auto_point2_temp.dev_attr.attr,
&sensor_dev_attr_pwm1_auto_point3_pwm.dev_attr.attr,
&sensor_dev_attr_pwm1_auto_point3_temp.dev_attr.attr,
&sensor_dev_attr_pwm1_auto_point4_pwm.dev_attr.attr,
&sensor_dev_attr_pwm1_auto_point4_temp.dev_attr.attr,
&sensor_dev_attr_pwm1_auto_point5_pwm.dev_attr.attr,
&sensor_dev_attr_pwm1_auto_point5_temp.dev_attr.attr,
&sensor_dev_attr_pwm1_auto_point6_pwm.dev_attr.attr,
&sensor_dev_attr_pwm1_auto_point6_temp.dev_attr.attr,
NULL
};
static const struct attribute_group gsc_hwmon_group = {
.attrs = gsc_hwmon_attributes,
};
__ATTRIBUTE_GROUPS(gsc_hwmon);
static int
gsc_hwmon_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
int channel, long *val)
{
struct gsc_hwmon_data *hwmon = dev_get_drvdata(dev);
const struct gsc_hwmon_channel *ch;
int sz, ret;
long tmp;
u8 buf[3];
switch (type) {
case hwmon_in:
ch = hwmon->in_ch[channel];
break;
case hwmon_temp:
ch = hwmon->temp_ch[channel];
break;
default:
return -EOPNOTSUPP;
}
sz = (ch->mode == mode_voltage) ? 3 : 2;
ret = regmap_bulk_read(hwmon->regmap, ch->reg, buf, sz);
if (ret)
return ret;
tmp = 0;
while (sz-- > 0)
tmp |= (buf[sz] << (8 * sz));
switch (ch->mode) {
case mode_temperature:
if (tmp > 0x8000)
tmp -= 0xffff;
break;
case mode_voltage_raw:
tmp = clamp_val(tmp, 0, BIT(GSC_HWMON_RESOLUTION));
/* scale based on ref voltage and ADC resolution */
tmp *= GSC_HWMON_VREF;
tmp >>= GSC_HWMON_RESOLUTION;
/* scale based on optional voltage divider */
if (ch->vdiv[0] && ch->vdiv[1]) {
tmp *= (ch->vdiv[0] + ch->vdiv[1]);
tmp /= ch->vdiv[1];
}
/* adjust by uV offset */
tmp += ch->mvoffset;
break;
case mode_voltage:
/* no adjustment needed */
break;
}
*val = tmp;
return 0;
}
static int
gsc_hwmon_read_string(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, const char **buf)
{
struct gsc_hwmon_data *hwmon = dev_get_drvdata(dev);
switch (type) {
case hwmon_in:
*buf = hwmon->in_ch[channel]->name;
break;
case hwmon_temp:
*buf = hwmon->temp_ch[channel]->name;
break;
default:
return -ENOTSUPP;
}
return 0;
}
static umode_t
gsc_hwmon_is_visible(const void *_data, enum hwmon_sensor_types type, u32 attr,
int ch)
{
return 0444;
}
static const struct hwmon_ops gsc_hwmon_ops = {
.is_visible = gsc_hwmon_is_visible,
.read = gsc_hwmon_read,
.read_string = gsc_hwmon_read_string,
};
static struct gsc_hwmon_platform_data *
gsc_hwmon_get_devtree_pdata(struct device *dev)
{
struct gsc_hwmon_platform_data *pdata;
struct gsc_hwmon_channel *ch;
struct fwnode_handle *child;
struct device_node *fan;
int nchannels;
nchannels = device_get_child_node_count(dev);
if (nchannels == 0)
return ERR_PTR(-ENODEV);
pdata = devm_kzalloc(dev,
sizeof(*pdata) + nchannels * sizeof(*ch),
GFP_KERNEL);
if (!pdata)
return ERR_PTR(-ENOMEM);
ch = (struct gsc_hwmon_channel *)(pdata + 1);
pdata->channels = ch;
pdata->nchannels = nchannels;
/* fan controller base address */
fan = of_find_compatible_node(dev->parent->of_node, NULL, "gw,gsc-fan");
if (fan && of_property_read_u32(fan, "reg", &pdata->fan_base)) {
dev_err(dev, "fan node without base\n");
return ERR_PTR(-EINVAL);
}
/* allocate structures for channels and count instances of each type */
device_for_each_child_node(dev, child) {
if (fwnode_property_read_string(child, "label", &ch->name)) {
dev_err(dev, "channel without label\n");
fwnode_handle_put(child);
return ERR_PTR(-EINVAL);
}
if (fwnode_property_read_u32(child, "reg", &ch->reg)) {
dev_err(dev, "channel without reg\n");
fwnode_handle_put(child);
return ERR_PTR(-EINVAL);
}
if (fwnode_property_read_u32(child, "gw,mode", &ch->mode)) {
dev_err(dev, "channel without mode\n");
fwnode_handle_put(child);
return ERR_PTR(-EINVAL);
}
if (ch->mode > mode_max) {
dev_err(dev, "invalid channel mode\n");
fwnode_handle_put(child);
return ERR_PTR(-EINVAL);
}
if (!fwnode_property_read_u32(child,
"gw,voltage-offset-microvolt",
&ch->mvoffset))
ch->mvoffset /= 1000;
fwnode_property_read_u32_array(child,
"gw,voltage-divider-ohms",
ch->vdiv, ARRAY_SIZE(ch->vdiv));
ch++;
}
return pdata;
}
static int gsc_hwmon_probe(struct platform_device *pdev)
{
struct gsc_dev *gsc = dev_get_drvdata(pdev->dev.parent);
struct device *dev = &pdev->dev;
struct device *hwmon_dev;
struct gsc_hwmon_platform_data *pdata = dev_get_platdata(dev);
struct gsc_hwmon_data *hwmon;
const struct attribute_group **groups;
int i, i_in, i_temp;
if (!pdata) {
pdata = gsc_hwmon_get_devtree_pdata(dev);
if (IS_ERR(pdata))
return PTR_ERR(pdata);
}
hwmon = devm_kzalloc(dev, sizeof(*hwmon), GFP_KERNEL);
if (!hwmon)
return -ENOMEM;
hwmon->gsc = gsc;
hwmon->pdata = pdata;
hwmon->regmap = devm_regmap_init(dev, &gsc_hwmon_regmap_bus,
gsc->i2c_hwmon,
&gsc_hwmon_regmap_config);
if (IS_ERR(hwmon->regmap))
return PTR_ERR(hwmon->regmap);
for (i = 0, i_in = 0, i_temp = 0; i < hwmon->pdata->nchannels; i++) {
const struct gsc_hwmon_channel *ch = &pdata->channels[i];
switch (ch->mode) {
case mode_temperature:
if (i_temp == GSC_HWMON_MAX_TEMP_CH) {
dev_err(gsc->dev, "too many temp channels\n");
return -EINVAL;
}
hwmon->temp_ch[i_temp] = ch;
hwmon->temp_config[i_temp] = HWMON_T_INPUT |
HWMON_T_LABEL;
i_temp++;
break;
case mode_voltage:
case mode_voltage_raw:
if (i_in == GSC_HWMON_MAX_IN_CH) {
dev_err(gsc->dev, "too many input channels\n");
return -EINVAL;
}
hwmon->in_ch[i_in] = ch;
hwmon->in_config[i_in] =
HWMON_I_INPUT | HWMON_I_LABEL;
i_in++;
break;
default:
dev_err(gsc->dev, "invalid mode: %d\n", ch->mode);
return -EINVAL;
}
}
/* setup config structures */
hwmon->chip.ops = &gsc_hwmon_ops;
hwmon->chip.info = hwmon->info;
hwmon->info[0] = &hwmon->temp_info;
hwmon->info[1] = &hwmon->in_info;
hwmon->temp_info.type = hwmon_temp;
hwmon->temp_info.config = hwmon->temp_config;
hwmon->in_info.type = hwmon_in;
hwmon->in_info.config = hwmon->in_config;
groups = pdata->fan_base ? gsc_hwmon_groups : NULL;
hwmon_dev = devm_hwmon_device_register_with_info(dev,
KBUILD_MODNAME, hwmon,
&hwmon->chip, groups);
return PTR_ERR_OR_ZERO(hwmon_dev);
}
static const struct of_device_id gsc_hwmon_of_match[] = {
{ .compatible = "gw,gsc-adc", },
{}
};
static struct platform_driver gsc_hwmon_driver = {
.driver = {
.name = "gsc-hwmon",
.of_match_table = gsc_hwmon_of_match,
},
.probe = gsc_hwmon_probe,
};
module_platform_driver(gsc_hwmon_driver);
MODULE_AUTHOR("Tim Harvey <tharvey@gateworks.com>");
MODULE_DESCRIPTION("GSC hardware monitor driver");
MODULE_LICENSE("GPL v2");
...@@ -692,6 +692,16 @@ config MESON_SARADC ...@@ -692,6 +692,16 @@ config MESON_SARADC
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called meson_saradc. module will be called meson_saradc.
config MP2629_ADC
tristate "Monolithic MP2629 ADC driver"
depends on MFD_MP2629
help
Say yes to have support for battery charger IC MP2629 ADC device
accessed over I2C.
This driver provides ADC conversion of system, input power supply
and battery voltage & current information.
config NAU7802 config NAU7802
tristate "Nuvoton NAU7802 ADC driver" tristate "Nuvoton NAU7802 ADC driver"
depends on I2C depends on I2C
......
...@@ -65,6 +65,7 @@ obj-$(CONFIG_MCP3911) += mcp3911.o ...@@ -65,6 +65,7 @@ obj-$(CONFIG_MCP3911) += mcp3911.o
obj-$(CONFIG_MEDIATEK_MT6577_AUXADC) += mt6577_auxadc.o obj-$(CONFIG_MEDIATEK_MT6577_AUXADC) += mt6577_auxadc.o
obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o
obj-$(CONFIG_MESON_SARADC) += meson_saradc.o obj-$(CONFIG_MESON_SARADC) += meson_saradc.o
obj-$(CONFIG_MP2629_ADC) += mp2629_adc.o
obj-$(CONFIG_MXS_LRADC_ADC) += mxs-lradc-adc.o obj-$(CONFIG_MXS_LRADC_ADC) += mxs-lradc-adc.o
obj-$(CONFIG_NAU7802) += nau7802.o obj-$(CONFIG_NAU7802) += nau7802.o
obj-$(CONFIG_NPCM_ADC) += npcm_adc.o obj-$(CONFIG_NPCM_ADC) += npcm_adc.o
......
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* MP2629 Driver for ADC
*
* Copyright 2020 Monolithic Power Systems, Inc
*
* Author: Saravanan Sekar <sravanhome@gmail.com>
*/
#include <linux/iio/driver.h>
#include <linux/iio/iio.h>
#include <linux/iio/machine.h>
#include <linux/mfd/mp2629.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#define MP2629_REG_ADC_CTRL 0x03
#define MP2629_REG_BATT_VOLT 0x0e
#define MP2629_REG_SYSTEM_VOLT 0x0f
#define MP2629_REG_INPUT_VOLT 0x11
#define MP2629_REG_BATT_CURRENT 0x12
#define MP2629_REG_INPUT_CURRENT 0x13
#define MP2629_ADC_START BIT(7)
#define MP2629_ADC_CONTINUOUS BIT(6)
#define MP2629_MAP(_mp, _mpc) IIO_MAP(#_mp, "mp2629_charger", "mp2629-"_mpc)
#define MP2629_ADC_CHAN(_ch, _type) { \
.type = _type, \
.indexed = 1, \
.datasheet_name = #_ch, \
.channel = MP2629_ ## _ch, \
.address = MP2629_REG_ ## _ch, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
}
struct mp2629_adc {
struct regmap *regmap;
struct device *dev;
};
static struct iio_chan_spec mp2629_channels[] = {
MP2629_ADC_CHAN(BATT_VOLT, IIO_VOLTAGE),
MP2629_ADC_CHAN(SYSTEM_VOLT, IIO_VOLTAGE),
MP2629_ADC_CHAN(INPUT_VOLT, IIO_VOLTAGE),
MP2629_ADC_CHAN(BATT_CURRENT, IIO_CURRENT),
MP2629_ADC_CHAN(INPUT_CURRENT, IIO_CURRENT)
};
static struct iio_map mp2629_adc_maps[] = {
MP2629_MAP(BATT_VOLT, "batt-volt"),
MP2629_MAP(SYSTEM_VOLT, "system-volt"),
MP2629_MAP(INPUT_VOLT, "input-volt"),
MP2629_MAP(BATT_CURRENT, "batt-current"),
MP2629_MAP(INPUT_CURRENT, "input-current")
};
static int mp2629_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
struct mp2629_adc *info = iio_priv(indio_dev);
unsigned int rval;
int ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
ret = regmap_read(info->regmap, chan->address, &rval);
if (ret)
return ret;
if (chan->address == MP2629_INPUT_VOLT)
rval &= GENMASK(6, 0);
*val = rval;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
switch (chan->channel) {
case MP2629_BATT_VOLT:
case MP2629_SYSTEM_VOLT:
*val = 20;
return IIO_VAL_INT;
case MP2629_INPUT_VOLT:
*val = 60;
return IIO_VAL_INT;
case MP2629_BATT_CURRENT:
*val = 175;
*val2 = 10;
return IIO_VAL_FRACTIONAL;
case MP2629_INPUT_CURRENT:
*val = 133;
*val2 = 10;
return IIO_VAL_FRACTIONAL;
default:
return -EINVAL;
}
default:
return -EINVAL;
}
}
static const struct iio_info mp2629_adc_info = {
.read_raw = &mp2629_read_raw,
};
static int mp2629_adc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct mp2629_data *ddata = dev_get_drvdata(dev->parent);
struct mp2629_adc *info;
struct iio_dev *indio_dev;
int ret;
indio_dev = devm_iio_device_alloc(dev, sizeof(*info));
if (!indio_dev)
return -ENOMEM;
info = iio_priv(indio_dev);
info->regmap = ddata->regmap;
info->dev = dev;
platform_set_drvdata(pdev, indio_dev);
ret = regmap_update_bits(info->regmap, MP2629_REG_ADC_CTRL,
MP2629_ADC_START | MP2629_ADC_CONTINUOUS,
MP2629_ADC_START | MP2629_ADC_CONTINUOUS);
if (ret) {
dev_err(dev, "adc enable fail: %d\n", ret);
return ret;
}
ret = iio_map_array_register(indio_dev, mp2629_adc_maps);
if (ret) {
dev_err(dev, "IIO maps register fail: %d\n", ret);
goto fail_disable;
}
indio_dev->name = "mp2629-adc";
indio_dev->dev.parent = dev;
indio_dev->channels = mp2629_channels;
indio_dev->num_channels = ARRAY_SIZE(mp2629_channels);
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &mp2629_adc_info;
ret = iio_device_register(indio_dev);
if (ret) {
dev_err(dev, "IIO device register fail: %d\n", ret);
goto fail_map_unregister;
}
return 0;
fail_map_unregister:
iio_map_array_unregister(indio_dev);
fail_disable:
regmap_update_bits(info->regmap, MP2629_REG_ADC_CTRL,
MP2629_ADC_CONTINUOUS, 0);
regmap_update_bits(info->regmap, MP2629_REG_ADC_CTRL,
MP2629_ADC_START, 0);
return ret;
}
static int mp2629_adc_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct mp2629_adc *info = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
iio_map_array_unregister(indio_dev);
regmap_update_bits(info->regmap, MP2629_REG_ADC_CTRL,
MP2629_ADC_CONTINUOUS, 0);
regmap_update_bits(info->regmap, MP2629_REG_ADC_CTRL,
MP2629_ADC_START, 0);
return 0;
}
static const struct of_device_id mp2629_adc_of_match[] = {
{ .compatible = "mps,mp2629_adc"},
{}
};
MODULE_DEVICE_TABLE(of, mp2629_adc_of_match);
static struct platform_driver mp2629_adc_driver = {
.driver = {
.name = "mp2629_adc",
.of_match_table = mp2629_adc_of_match,
},
.probe = mp2629_adc_probe,
.remove = mp2629_adc_remove,
};
module_platform_driver(mp2629_adc_driver);
MODULE_AUTHOR("Saravanan Sekar <sravanhome@gmail.com>");
MODULE_DESCRIPTION("MP2629 ADC driver");
MODULE_LICENSE("GPL");
...@@ -407,6 +407,21 @@ config MFD_EXYNOS_LPASS ...@@ -407,6 +407,21 @@ config MFD_EXYNOS_LPASS
Select this option to enable support for Samsung Exynos Low Power Select this option to enable support for Samsung Exynos Low Power
Audio Subsystem. Audio Subsystem.
config MFD_GATEWORKS_GSC
tristate "Gateworks System Controller"
depends on (I2C && OF)
select MFD_CORE
select REGMAP_I2C
select REGMAP_IRQ
help
Enable support for the Gateworks System Controller (GSC) found
on Gateworks Single Board Computers supporting system functions
such as push-button monitor, multiple ADC's for voltage and
temperature monitoring, fan controller and watchdog monitor.
This driver provides common support for accessing the device.
Additional drivers must be enabled in order to use the
functionality of the device.
config MFD_MC13XXX config MFD_MC13XXX
tristate tristate
depends on (SPI_MASTER || I2C) depends on (SPI_MASTER || I2C)
...@@ -434,6 +449,15 @@ config MFD_MC13XXX_I2C ...@@ -434,6 +449,15 @@ config MFD_MC13XXX_I2C
help help
Select this if your MC13xxx is connected via an I2C bus. Select this if your MC13xxx is connected via an I2C bus.
config MFD_MP2629
tristate "Monolithic Power Systems MP2629 ADC and Battery charger"
depends on I2C
select REGMAP_I2C
help
Select this option to enable support for Monolithic Power Systems
battery charger. This provides ADC, thermal and battery charger power
management functions.
config MFD_MXS_LRADC config MFD_MXS_LRADC
tristate "Freescale i.MX23/i.MX28 LRADC" tristate "Freescale i.MX23/i.MX28 LRADC"
depends on ARCH_MXS || COMPILE_TEST depends on ARCH_MXS || COMPILE_TEST
......
...@@ -15,6 +15,7 @@ obj-$(CONFIG_MFD_BCM590XX) += bcm590xx.o ...@@ -15,6 +15,7 @@ obj-$(CONFIG_MFD_BCM590XX) += bcm590xx.o
obj-$(CONFIG_MFD_BD9571MWV) += bd9571mwv.o obj-$(CONFIG_MFD_BD9571MWV) += bd9571mwv.o
obj-$(CONFIG_MFD_CROS_EC_DEV) += cros_ec_dev.o obj-$(CONFIG_MFD_CROS_EC_DEV) += cros_ec_dev.o
obj-$(CONFIG_MFD_EXYNOS_LPASS) += exynos-lpass.o obj-$(CONFIG_MFD_EXYNOS_LPASS) += exynos-lpass.o
obj-$(CONFIG_MFD_GATEWORKS_GSC) += gateworks-gsc.o
obj-$(CONFIG_HTC_PASIC3) += htc-pasic3.o obj-$(CONFIG_HTC_PASIC3) += htc-pasic3.o
obj-$(CONFIG_HTC_I2CPLD) += htc-i2cpld.o obj-$(CONFIG_HTC_I2CPLD) += htc-i2cpld.o
...@@ -170,6 +171,8 @@ obj-$(CONFIG_MFD_MAX8925) += max8925.o ...@@ -170,6 +171,8 @@ obj-$(CONFIG_MFD_MAX8925) += max8925.o
obj-$(CONFIG_MFD_MAX8997) += max8997.o max8997-irq.o obj-$(CONFIG_MFD_MAX8997) += max8997.o max8997-irq.o
obj-$(CONFIG_MFD_MAX8998) += max8998.o max8998-irq.o obj-$(CONFIG_MFD_MAX8998) += max8998.o max8998-irq.o
obj-$(CONFIG_MFD_MP2629) += mp2629.o
pcf50633-objs := pcf50633-core.o pcf50633-irq.o pcf50633-objs := pcf50633-core.o pcf50633-irq.o
obj-$(CONFIG_MFD_PCF50633) += pcf50633.o obj-$(CONFIG_MFD_PCF50633) += pcf50633.o
obj-$(CONFIG_PCF50633_ADC) += pcf50633-adc.o obj-$(CONFIG_PCF50633_ADC) += pcf50633-adc.o
...@@ -240,7 +243,7 @@ obj-$(CONFIG_INTEL_SOC_PMIC) += intel-soc-pmic.o ...@@ -240,7 +243,7 @@ obj-$(CONFIG_INTEL_SOC_PMIC) += intel-soc-pmic.o
obj-$(CONFIG_INTEL_SOC_PMIC_BXTWC) += intel_soc_pmic_bxtwc.o obj-$(CONFIG_INTEL_SOC_PMIC_BXTWC) += intel_soc_pmic_bxtwc.o
obj-$(CONFIG_INTEL_SOC_PMIC_CHTWC) += intel_soc_pmic_chtwc.o obj-$(CONFIG_INTEL_SOC_PMIC_CHTWC) += intel_soc_pmic_chtwc.o
obj-$(CONFIG_INTEL_SOC_PMIC_CHTDC_TI) += intel_soc_pmic_chtdc_ti.o obj-$(CONFIG_INTEL_SOC_PMIC_CHTDC_TI) += intel_soc_pmic_chtdc_ti.o
mt6397-objs := mt6397-core.o mt6397-irq.o mt6397-objs := mt6397-core.o mt6397-irq.o mt6358-irq.o
obj-$(CONFIG_MFD_MT6397) += mt6397.o obj-$(CONFIG_MFD_MT6397) += mt6397.o
obj-$(CONFIG_INTEL_SOC_PMIC_MRFLD) += intel_soc_pmic_mrfld.o obj-$(CONFIG_INTEL_SOC_PMIC_MRFLD) += intel_soc_pmic_mrfld.o
......
// SPDX-License-Identifier: GPL-2.0
/*
* The Gateworks System Controller (GSC) is a multi-function
* device designed for use in Gateworks Single Board Computers.
* The control interface is I2C, with an interrupt. The device supports
* system functions such as push-button monitoring, multiple ADC's for
* voltage and temperature monitoring, fan controller and watchdog monitor.
*
* Copyright (C) 2020 Gateworks Corporation
*/
#include <linux/device.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/mfd/gsc.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <asm/unaligned.h>
/*
* The GSC suffers from an errata where occasionally during
* ADC cycles the chip can NAK I2C transactions. To ensure we have reliable
* register access we place retries around register access.
*/
#define I2C_RETRIES 3
int gsc_write(void *context, unsigned int reg, unsigned int val)
{
struct i2c_client *client = context;
int retry, ret;
for (retry = 0; retry < I2C_RETRIES; retry++) {
ret = i2c_smbus_write_byte_data(client, reg, val);
/*
* -EAGAIN returned when the i2c host controller is busy
* -EIO returned when i2c device is busy
*/
if (ret != -EAGAIN && ret != -EIO)
break;
}
return 0;
}
EXPORT_SYMBOL_GPL(gsc_write);
int gsc_read(void *context, unsigned int reg, unsigned int *val)
{
struct i2c_client *client = context;
int retry, ret;
for (retry = 0; retry < I2C_RETRIES; retry++) {
ret = i2c_smbus_read_byte_data(client, reg);
/*
* -EAGAIN returned when the i2c host controller is busy
* -EIO returned when i2c device is busy
*/
if (ret != -EAGAIN && ret != -EIO)
break;
}
*val = ret & 0xff;
return 0;
}
EXPORT_SYMBOL_GPL(gsc_read);
/*
* gsc_powerdown - API to use GSC to power down board for a specific time
*
* secs - number of seconds to remain powered off
*/
static int gsc_powerdown(struct gsc_dev *gsc, unsigned long secs)
{
int ret;
unsigned char regs[4];
dev_info(&gsc->i2c->dev, "GSC powerdown for %ld seconds\n",
secs);
put_unaligned_le32(secs, regs);
ret = regmap_bulk_write(gsc->regmap, GSC_TIME_ADD, regs, 4);
if (ret)
return ret;
ret = regmap_update_bits(gsc->regmap, GSC_CTRL_1,
BIT(GSC_CTRL_1_SLEEP_ADD),
BIT(GSC_CTRL_1_SLEEP_ADD));
if (ret)
return ret;
ret = regmap_update_bits(gsc->regmap, GSC_CTRL_1,
BIT(GSC_CTRL_1_SLEEP_ACTIVATE) |
BIT(GSC_CTRL_1_SLEEP_ENABLE),
BIT(GSC_CTRL_1_SLEEP_ACTIVATE) |
BIT(GSC_CTRL_1_SLEEP_ENABLE));
return ret;
}
static ssize_t gsc_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct gsc_dev *gsc = dev_get_drvdata(dev);
const char *name = attr->attr.name;
int rz = 0;
if (strcasecmp(name, "fw_version") == 0)
rz = sprintf(buf, "%d\n", gsc->fwver);
else if (strcasecmp(name, "fw_crc") == 0)
rz = sprintf(buf, "0x%04x\n", gsc->fwcrc);
else
dev_err(dev, "invalid command: '%s'\n", name);
return rz;
}
static ssize_t gsc_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct gsc_dev *gsc = dev_get_drvdata(dev);
const char *name = attr->attr.name;
long value;
if (strcasecmp(name, "powerdown") == 0) {
if (kstrtol(buf, 0, &value) == 0)
gsc_powerdown(gsc, value);
} else {
dev_err(dev, "invalid command: '%s\n", name);
}
return count;
}
static struct device_attribute attr_fwver =
__ATTR(fw_version, 0440, gsc_show, NULL);
static struct device_attribute attr_fwcrc =
__ATTR(fw_crc, 0440, gsc_show, NULL);
static struct device_attribute attr_pwrdown =
__ATTR(powerdown, 0220, NULL, gsc_store);
static struct attribute *gsc_attrs[] = {
&attr_fwver.attr,
&attr_fwcrc.attr,
&attr_pwrdown.attr,
NULL,
};
static struct attribute_group attr_group = {
.attrs = gsc_attrs,
};
static const struct of_device_id gsc_of_match[] = {
{ .compatible = "gw,gsc", },
{ }
};
MODULE_DEVICE_TABLE(of, gsc_of_match);
static struct regmap_bus gsc_regmap_bus = {
.reg_read = gsc_read,
.reg_write = gsc_write,
};
static const struct regmap_config gsc_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.cache_type = REGCACHE_NONE,
.max_register = GSC_WP,
};
static const struct regmap_irq gsc_irqs[] = {
REGMAP_IRQ_REG(GSC_IRQ_PB, 0, BIT(GSC_IRQ_PB)),
REGMAP_IRQ_REG(GSC_IRQ_KEY_ERASED, 0, BIT(GSC_IRQ_KEY_ERASED)),
REGMAP_IRQ_REG(GSC_IRQ_EEPROM_WP, 0, BIT(GSC_IRQ_EEPROM_WP)),
REGMAP_IRQ_REG(GSC_IRQ_RESV, 0, BIT(GSC_IRQ_RESV)),
REGMAP_IRQ_REG(GSC_IRQ_GPIO, 0, BIT(GSC_IRQ_GPIO)),
REGMAP_IRQ_REG(GSC_IRQ_TAMPER, 0, BIT(GSC_IRQ_TAMPER)),
REGMAP_IRQ_REG(GSC_IRQ_WDT_TIMEOUT, 0, BIT(GSC_IRQ_WDT_TIMEOUT)),
REGMAP_IRQ_REG(GSC_IRQ_SWITCH_HOLD, 0, BIT(GSC_IRQ_SWITCH_HOLD)),
};
static const struct regmap_irq_chip gsc_irq_chip = {
.name = "gateworks-gsc",
.irqs = gsc_irqs,
.num_irqs = ARRAY_SIZE(gsc_irqs),
.num_regs = 1,
.status_base = GSC_IRQ_STATUS,
.mask_base = GSC_IRQ_ENABLE,
.mask_invert = true,
.ack_base = GSC_IRQ_STATUS,
.ack_invert = true,
};
static int gsc_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct gsc_dev *gsc;
struct regmap_irq_chip_data *irq_data;
int ret;
unsigned int reg;
gsc = devm_kzalloc(dev, sizeof(*gsc), GFP_KERNEL);
if (!gsc)
return -ENOMEM;
gsc->dev = &client->dev;
gsc->i2c = client;
i2c_set_clientdata(client, gsc);
gsc->regmap = devm_regmap_init(dev, &gsc_regmap_bus, client,
&gsc_regmap_config);
if (IS_ERR(gsc->regmap))
return PTR_ERR(gsc->regmap);
if (regmap_read(gsc->regmap, GSC_FW_VER, &reg))
return -EIO;
gsc->fwver = reg;
regmap_read(gsc->regmap, GSC_FW_CRC, &reg);
gsc->fwcrc = reg;
regmap_read(gsc->regmap, GSC_FW_CRC + 1, &reg);
gsc->fwcrc |= reg << 8;
gsc->i2c_hwmon = devm_i2c_new_dummy_device(dev, client->adapter,
GSC_HWMON);
if (IS_ERR(gsc->i2c_hwmon)) {
dev_err(dev, "Failed to allocate I2C device for HWMON\n");
return PTR_ERR(gsc->i2c_hwmon);
}
ret = devm_regmap_add_irq_chip(dev, gsc->regmap, client->irq,
IRQF_ONESHOT | IRQF_SHARED |
IRQF_TRIGGER_FALLING, 0,
&gsc_irq_chip, &irq_data);
if (ret)
return ret;
dev_info(dev, "Gateworks System Controller v%d: fw 0x%04x\n",
gsc->fwver, gsc->fwcrc);
ret = sysfs_create_group(&dev->kobj, &attr_group);
if (ret)
dev_err(dev, "failed to create sysfs attrs\n");
ret = devm_of_platform_populate(dev);
if (ret) {
sysfs_remove_group(&dev->kobj, &attr_group);
return ret;
}
return 0;
}
static int gsc_remove(struct i2c_client *client)
{
sysfs_remove_group(&client->dev.kobj, &attr_group);
return 0;
}
static struct i2c_driver gsc_driver = {
.driver = {
.name = "gateworks-gsc",
.of_match_table = gsc_of_match,
},
.probe_new = gsc_probe,
.remove = gsc_remove,
};
module_i2c_driver(gsc_driver);
MODULE_AUTHOR("Tim Harvey <tharvey@gateworks.com>");
MODULE_DESCRIPTION("I2C Core interface for GSC");
MODULE_LICENSE("GPL v2");
// SPDX-License-Identifier: GPL-2.0+
/*
* MP2629 parent driver for ADC and battery charger
*
* Copyright 2020 Monolithic Power Systems, Inc
*
* Author: Saravanan Sekar <sravanhome@gmail.com>
*/
#include <linux/i2c.h>
#include <linux/kernel.h>
#include <linux/mfd/core.h>
#include <linux/mfd/mp2629.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/slab.h>
static const struct mfd_cell mp2629_cell[] = {
{
.name = "mp2629_adc",
.of_compatible = "mps,mp2629_adc",
},
{
.name = "mp2629_charger",
.of_compatible = "mps,mp2629_charger",
}
};
static const struct regmap_config mp2629_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = 0x17,
};
static int mp2629_probe(struct i2c_client *client)
{
struct mp2629_data *ddata;
int ret;
ddata = devm_kzalloc(&client->dev, sizeof(*ddata), GFP_KERNEL);
if (!ddata)
return -ENOMEM;
ddata->dev = &client->dev;
i2c_set_clientdata(client, ddata);
ddata->regmap = devm_regmap_init_i2c(client, &mp2629_regmap_config);
if (IS_ERR(ddata->regmap)) {
dev_err(ddata->dev, "Failed to allocate regmap\n");
return PTR_ERR(ddata->regmap);
}
ret = devm_mfd_add_devices(ddata->dev, PLATFORM_DEVID_AUTO, mp2629_cell,
ARRAY_SIZE(mp2629_cell), NULL, 0, NULL);
if (ret)
dev_err(ddata->dev, "Failed to register sub-devices %d\n", ret);
return ret;
}
static const struct of_device_id mp2629_of_match[] = {
{ .compatible = "mps,mp2629"},
{ }
};
MODULE_DEVICE_TABLE(of, mp2629_of_match);
static struct i2c_driver mp2629_driver = {
.driver = {
.name = "mp2629",
.of_match_table = mp2629_of_match,
},
.probe_new = mp2629_probe,
};
module_i2c_driver(mp2629_driver);
MODULE_AUTHOR("Saravanan Sekar <sravanhome@gmail.com>");
MODULE_DESCRIPTION("MP2629 Battery charger parent driver");
MODULE_LICENSE("GPL");
// SPDX-License-Identifier: GPL-2.0
//
// Copyright (c) 2020 MediaTek Inc.
#include <linux/interrupt.h>
#include <linux/mfd/mt6358/core.h>
#include <linux/mfd/mt6358/registers.h>
#include <linux/mfd/mt6397/core.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
static struct irq_top_t mt6358_ints[] = {
MT6358_TOP_GEN(BUCK),
MT6358_TOP_GEN(LDO),
MT6358_TOP_GEN(PSC),
MT6358_TOP_GEN(SCK),
MT6358_TOP_GEN(BM),
MT6358_TOP_GEN(HK),
MT6358_TOP_GEN(AUD),
MT6358_TOP_GEN(MISC),
};
static void pmic_irq_enable(struct irq_data *data)
{
unsigned int hwirq = irqd_to_hwirq(data);
struct mt6397_chip *chip = irq_data_get_irq_chip_data(data);
struct pmic_irq_data *irqd = chip->irq_data;
irqd->enable_hwirq[hwirq] = true;
}
static void pmic_irq_disable(struct irq_data *data)
{
unsigned int hwirq = irqd_to_hwirq(data);
struct mt6397_chip *chip = irq_data_get_irq_chip_data(data);
struct pmic_irq_data *irqd = chip->irq_data;
irqd->enable_hwirq[hwirq] = false;
}
static void pmic_irq_lock(struct irq_data *data)
{
struct mt6397_chip *chip = irq_data_get_irq_chip_data(data);
mutex_lock(&chip->irqlock);
}
static void pmic_irq_sync_unlock(struct irq_data *data)
{
unsigned int i, top_gp, gp_offset, en_reg, int_regs, shift;
struct mt6397_chip *chip = irq_data_get_irq_chip_data(data);
struct pmic_irq_data *irqd = chip->irq_data;
for (i = 0; i < irqd->num_pmic_irqs; i++) {
if (irqd->enable_hwirq[i] == irqd->cache_hwirq[i])
continue;
/* Find out the IRQ group */
top_gp = 0;
while ((top_gp + 1) < irqd->num_top &&
i >= mt6358_ints[top_gp + 1].hwirq_base)
top_gp++;
/* Find the IRQ registers */
gp_offset = i - mt6358_ints[top_gp].hwirq_base;
int_regs = gp_offset / MT6358_REG_WIDTH;
shift = gp_offset % MT6358_REG_WIDTH;
en_reg = mt6358_ints[top_gp].en_reg +
(mt6358_ints[top_gp].en_reg_shift * int_regs);
regmap_update_bits(chip->regmap, en_reg, BIT(shift),
irqd->enable_hwirq[i] << shift);
irqd->cache_hwirq[i] = irqd->enable_hwirq[i];
}
mutex_unlock(&chip->irqlock);
}
static struct irq_chip mt6358_irq_chip = {
.name = "mt6358-irq",
.flags = IRQCHIP_SKIP_SET_WAKE,
.irq_enable = pmic_irq_enable,
.irq_disable = pmic_irq_disable,
.irq_bus_lock = pmic_irq_lock,
.irq_bus_sync_unlock = pmic_irq_sync_unlock,
};
static void mt6358_irq_sp_handler(struct mt6397_chip *chip,
unsigned int top_gp)
{
unsigned int irq_status, sta_reg, status;
unsigned int hwirq, virq;
int i, j, ret;
for (i = 0; i < mt6358_ints[top_gp].num_int_regs; i++) {
sta_reg = mt6358_ints[top_gp].sta_reg +
mt6358_ints[top_gp].sta_reg_shift * i;
ret = regmap_read(chip->regmap, sta_reg, &irq_status);
if (ret) {
dev_err(chip->dev,
"Failed to read IRQ status, ret=%d\n", ret);
return;
}
if (!irq_status)
continue;
status = irq_status;
do {
j = __ffs(status);
hwirq = mt6358_ints[top_gp].hwirq_base +
MT6358_REG_WIDTH * i + j;
virq = irq_find_mapping(chip->irq_domain, hwirq);
if (virq)
handle_nested_irq(virq);
status &= ~BIT(j);
} while (status);
regmap_write(chip->regmap, sta_reg, irq_status);
}
}
static irqreturn_t mt6358_irq_handler(int irq, void *data)
{
struct mt6397_chip *chip = data;
struct pmic_irq_data *mt6358_irq_data = chip->irq_data;
unsigned int bit, i, top_irq_status = 0;
int ret;
ret = regmap_read(chip->regmap,
mt6358_irq_data->top_int_status_reg,
&top_irq_status);
if (ret) {
dev_err(chip->dev,
"Failed to read status from the device, ret=%d\n", ret);
return IRQ_NONE;
}
for (i = 0; i < mt6358_irq_data->num_top; i++) {
bit = BIT(mt6358_ints[i].top_offset);
if (top_irq_status & bit) {
mt6358_irq_sp_handler(chip, i);
top_irq_status &= ~bit;
if (!top_irq_status)
break;
}
}
return IRQ_HANDLED;
}
static int pmic_irq_domain_map(struct irq_domain *d, unsigned int irq,
irq_hw_number_t hw)
{
struct mt6397_chip *mt6397 = d->host_data;
irq_set_chip_data(irq, mt6397);
irq_set_chip_and_handler(irq, &mt6358_irq_chip, handle_level_irq);
irq_set_nested_thread(irq, 1);
irq_set_noprobe(irq);
return 0;
}
static const struct irq_domain_ops mt6358_irq_domain_ops = {
.map = pmic_irq_domain_map,
.xlate = irq_domain_xlate_twocell,
};
int mt6358_irq_init(struct mt6397_chip *chip)
{
int i, j, ret;
struct pmic_irq_data *irqd;
irqd = devm_kzalloc(chip->dev, sizeof(*irqd), GFP_KERNEL);
if (!irqd)
return -ENOMEM;
chip->irq_data = irqd;
mutex_init(&chip->irqlock);
irqd->top_int_status_reg = MT6358_TOP_INT_STATUS0;
irqd->num_pmic_irqs = MT6358_IRQ_NR;
irqd->num_top = ARRAY_SIZE(mt6358_ints);
irqd->enable_hwirq = devm_kcalloc(chip->dev,
irqd->num_pmic_irqs,
sizeof(*irqd->enable_hwirq),
GFP_KERNEL);
if (!irqd->enable_hwirq)
return -ENOMEM;
irqd->cache_hwirq = devm_kcalloc(chip->dev,
irqd->num_pmic_irqs,
sizeof(*irqd->cache_hwirq),
GFP_KERNEL);
if (!irqd->cache_hwirq)
return -ENOMEM;
/* Disable all interrupts for initializing */
for (i = 0; i < irqd->num_top; i++) {
for (j = 0; j < mt6358_ints[i].num_int_regs; j++)
regmap_write(chip->regmap,
mt6358_ints[i].en_reg +
mt6358_ints[i].en_reg_shift * j, 0);
}
chip->irq_domain = irq_domain_add_linear(chip->dev->of_node,
irqd->num_pmic_irqs,
&mt6358_irq_domain_ops, chip);
if (!chip->irq_domain) {
dev_err(chip->dev, "Could not create IRQ domain\n");
return -ENODEV;
}
ret = devm_request_threaded_irq(chip->dev, chip->irq, NULL,
mt6358_irq_handler, IRQF_ONESHOT,
mt6358_irq_chip.name, chip);
if (ret) {
dev_err(chip->dev, "Failed to register IRQ=%d, ret=%d\n",
chip->irq, ret);
return ret;
}
enable_irq_wake(chip->irq);
return ret;
}
...@@ -12,13 +12,18 @@ ...@@ -12,13 +12,18 @@
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/mfd/core.h> #include <linux/mfd/core.h>
#include <linux/mfd/mt6323/core.h> #include <linux/mfd/mt6323/core.h>
#include <linux/mfd/mt6358/core.h>
#include <linux/mfd/mt6397/core.h> #include <linux/mfd/mt6397/core.h>
#include <linux/mfd/mt6323/registers.h> #include <linux/mfd/mt6323/registers.h>
#include <linux/mfd/mt6358/registers.h>
#include <linux/mfd/mt6397/registers.h> #include <linux/mfd/mt6397/registers.h>
#define MT6323_RTC_BASE 0x8000 #define MT6323_RTC_BASE 0x8000
#define MT6323_RTC_SIZE 0x40 #define MT6323_RTC_SIZE 0x40
#define MT6358_RTC_BASE 0x0588
#define MT6358_RTC_SIZE 0x3c
#define MT6397_RTC_BASE 0xe000 #define MT6397_RTC_BASE 0xe000
#define MT6397_RTC_SIZE 0x3e #define MT6397_RTC_SIZE 0x3e
...@@ -30,6 +35,11 @@ static const struct resource mt6323_rtc_resources[] = { ...@@ -30,6 +35,11 @@ static const struct resource mt6323_rtc_resources[] = {
DEFINE_RES_IRQ(MT6323_IRQ_STATUS_RTC), DEFINE_RES_IRQ(MT6323_IRQ_STATUS_RTC),
}; };
static const struct resource mt6358_rtc_resources[] = {
DEFINE_RES_MEM(MT6358_RTC_BASE, MT6358_RTC_SIZE),
DEFINE_RES_IRQ(MT6358_IRQ_RTC),
};
static const struct resource mt6397_rtc_resources[] = { static const struct resource mt6397_rtc_resources[] = {
DEFINE_RES_MEM(MT6397_RTC_BASE, MT6397_RTC_SIZE), DEFINE_RES_MEM(MT6397_RTC_BASE, MT6397_RTC_SIZE),
DEFINE_RES_IRQ(MT6397_IRQ_RTC), DEFINE_RES_IRQ(MT6397_IRQ_RTC),
...@@ -74,6 +84,21 @@ static const struct mfd_cell mt6323_devs[] = { ...@@ -74,6 +84,21 @@ static const struct mfd_cell mt6323_devs[] = {
}, },
}; };
static const struct mfd_cell mt6358_devs[] = {
{
.name = "mt6358-regulator",
.of_compatible = "mediatek,mt6358-regulator"
}, {
.name = "mt6358-rtc",
.num_resources = ARRAY_SIZE(mt6358_rtc_resources),
.resources = mt6358_rtc_resources,
.of_compatible = "mediatek,mt6358-rtc",
}, {
.name = "mt6358-sound",
.of_compatible = "mediatek,mt6358-sound"
},
};
static const struct mfd_cell mt6397_devs[] = { static const struct mfd_cell mt6397_devs[] = {
{ {
.name = "mt6397-rtc", .name = "mt6397-rtc",
...@@ -100,54 +125,42 @@ static const struct mfd_cell mt6397_devs[] = { ...@@ -100,54 +125,42 @@ static const struct mfd_cell mt6397_devs[] = {
} }
}; };
#ifdef CONFIG_PM_SLEEP
static int mt6397_irq_suspend(struct device *dev)
{
struct mt6397_chip *chip = dev_get_drvdata(dev);
regmap_write(chip->regmap, chip->int_con[0], chip->wake_mask[0]);
regmap_write(chip->regmap, chip->int_con[1], chip->wake_mask[1]);
enable_irq_wake(chip->irq);
return 0;
}
static int mt6397_irq_resume(struct device *dev)
{
struct mt6397_chip *chip = dev_get_drvdata(dev);
regmap_write(chip->regmap, chip->int_con[0], chip->irq_masks_cur[0]);
regmap_write(chip->regmap, chip->int_con[1], chip->irq_masks_cur[1]);
disable_irq_wake(chip->irq);
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(mt6397_pm_ops, mt6397_irq_suspend,
mt6397_irq_resume);
struct chip_data { struct chip_data {
u32 cid_addr; u32 cid_addr;
u32 cid_shift; u32 cid_shift;
const struct mfd_cell *cells;
int cell_size;
int (*irq_init)(struct mt6397_chip *chip);
}; };
static const struct chip_data mt6323_core = { static const struct chip_data mt6323_core = {
.cid_addr = MT6323_CID, .cid_addr = MT6323_CID,
.cid_shift = 0, .cid_shift = 0,
.cells = mt6323_devs,
.cell_size = ARRAY_SIZE(mt6323_devs),
.irq_init = mt6397_irq_init,
};
static const struct chip_data mt6358_core = {
.cid_addr = MT6358_SWCID,
.cid_shift = 8,
.cells = mt6358_devs,
.cell_size = ARRAY_SIZE(mt6358_devs),
.irq_init = mt6358_irq_init,
}; };
static const struct chip_data mt6397_core = { static const struct chip_data mt6397_core = {
.cid_addr = MT6397_CID, .cid_addr = MT6397_CID,
.cid_shift = 0, .cid_shift = 0,
.cells = mt6397_devs,
.cell_size = ARRAY_SIZE(mt6397_devs),
.irq_init = mt6397_irq_init,
}; };
static int mt6397_probe(struct platform_device *pdev) static int mt6397_probe(struct platform_device *pdev)
{ {
int ret; int ret;
unsigned int id; unsigned int id = 0;
struct mt6397_chip *pmic; struct mt6397_chip *pmic;
const struct chip_data *pmic_core; const struct chip_data *pmic_core;
...@@ -183,29 +196,13 @@ static int mt6397_probe(struct platform_device *pdev) ...@@ -183,29 +196,13 @@ static int mt6397_probe(struct platform_device *pdev)
if (pmic->irq <= 0) if (pmic->irq <= 0)
return pmic->irq; return pmic->irq;
ret = mt6397_irq_init(pmic); ret = pmic_core->irq_init(pmic);
if (ret) if (ret)
return ret; return ret;
switch (pmic->chip_id) { ret = devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE,
case MT6323_CHIP_ID: pmic_core->cells, pmic_core->cell_size,
ret = devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE, NULL, 0, pmic->irq_domain);
mt6323_devs, ARRAY_SIZE(mt6323_devs),
NULL, 0, pmic->irq_domain);
break;
case MT6391_CHIP_ID:
case MT6397_CHIP_ID:
ret = devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE,
mt6397_devs, ARRAY_SIZE(mt6397_devs),
NULL, 0, pmic->irq_domain);
break;
default:
dev_err(&pdev->dev, "unsupported chip: %d\n", pmic->chip_id);
return -ENODEV;
}
if (ret) { if (ret) {
irq_domain_remove(pmic->irq_domain); irq_domain_remove(pmic->irq_domain);
dev_err(&pdev->dev, "failed to add child devices: %d\n", ret); dev_err(&pdev->dev, "failed to add child devices: %d\n", ret);
...@@ -218,6 +215,9 @@ static const struct of_device_id mt6397_of_match[] = { ...@@ -218,6 +215,9 @@ static const struct of_device_id mt6397_of_match[] = {
{ {
.compatible = "mediatek,mt6323", .compatible = "mediatek,mt6323",
.data = &mt6323_core, .data = &mt6323_core,
}, {
.compatible = "mediatek,mt6358",
.data = &mt6358_core,
}, { }, {
.compatible = "mediatek,mt6397", .compatible = "mediatek,mt6397",
.data = &mt6397_core, .data = &mt6397_core,
...@@ -238,7 +238,6 @@ static struct platform_driver mt6397_driver = { ...@@ -238,7 +238,6 @@ static struct platform_driver mt6397_driver = {
.driver = { .driver = {
.name = "mt6397", .name = "mt6397",
.of_match_table = of_match_ptr(mt6397_of_match), .of_match_table = of_match_ptr(mt6397_of_match),
.pm = &mt6397_pm_ops,
}, },
.id_table = mt6397_id, .id_table = mt6397_id,
}; };
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <linux/of_irq.h> #include <linux/of_irq.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/suspend.h>
#include <linux/mfd/mt6323/core.h> #include <linux/mfd/mt6323/core.h>
#include <linux/mfd/mt6323/registers.h> #include <linux/mfd/mt6323/registers.h>
#include <linux/mfd/mt6397/core.h> #include <linux/mfd/mt6397/core.h>
...@@ -81,7 +82,7 @@ static struct irq_chip mt6397_irq_chip = { ...@@ -81,7 +82,7 @@ static struct irq_chip mt6397_irq_chip = {
static void mt6397_irq_handle_reg(struct mt6397_chip *mt6397, int reg, static void mt6397_irq_handle_reg(struct mt6397_chip *mt6397, int reg,
int irqbase) int irqbase)
{ {
unsigned int status; unsigned int status = 0;
int i, irq, ret; int i, irq, ret;
ret = regmap_read(mt6397->regmap, reg, &status); ret = regmap_read(mt6397->regmap, reg, &status);
...@@ -128,6 +129,36 @@ static const struct irq_domain_ops mt6397_irq_domain_ops = { ...@@ -128,6 +129,36 @@ static const struct irq_domain_ops mt6397_irq_domain_ops = {
.map = mt6397_irq_domain_map, .map = mt6397_irq_domain_map,
}; };
static int mt6397_irq_pm_notifier(struct notifier_block *notifier,
unsigned long pm_event, void *unused)
{
struct mt6397_chip *chip =
container_of(notifier, struct mt6397_chip, pm_nb);
switch (pm_event) {
case PM_SUSPEND_PREPARE:
regmap_write(chip->regmap,
chip->int_con[0], chip->wake_mask[0]);
regmap_write(chip->regmap,
chip->int_con[1], chip->wake_mask[1]);
enable_irq_wake(chip->irq);
break;
case PM_POST_SUSPEND:
regmap_write(chip->regmap,
chip->int_con[0], chip->irq_masks_cur[0]);
regmap_write(chip->regmap,
chip->int_con[1], chip->irq_masks_cur[1]);
disable_irq_wake(chip->irq);
break;
default:
break;
}
return NOTIFY_DONE;
}
int mt6397_irq_init(struct mt6397_chip *chip) int mt6397_irq_init(struct mt6397_chip *chip)
{ {
int ret; int ret;
...@@ -159,6 +190,7 @@ int mt6397_irq_init(struct mt6397_chip *chip) ...@@ -159,6 +190,7 @@ int mt6397_irq_init(struct mt6397_chip *chip)
regmap_write(chip->regmap, chip->int_con[0], 0x0); regmap_write(chip->regmap, chip->int_con[0], 0x0);
regmap_write(chip->regmap, chip->int_con[1], 0x0); regmap_write(chip->regmap, chip->int_con[1], 0x0);
chip->pm_nb.notifier_call = mt6397_irq_pm_notifier;
chip->irq_domain = irq_domain_add_linear(chip->dev->of_node, chip->irq_domain = irq_domain_add_linear(chip->dev->of_node,
MT6397_IRQ_NR, MT6397_IRQ_NR,
&mt6397_irq_domain_ops, &mt6397_irq_domain_ops,
...@@ -177,5 +209,6 @@ int mt6397_irq_init(struct mt6397_chip *chip) ...@@ -177,5 +209,6 @@ int mt6397_irq_init(struct mt6397_chip *chip)
return ret; return ret;
} }
register_pm_notifier(&chip->pm_nb);
return 0; return 0;
} }
...@@ -30,7 +30,7 @@ static void mt6323_do_pwroff(void) ...@@ -30,7 +30,7 @@ static void mt6323_do_pwroff(void)
int ret; int ret;
regmap_write(pwrc->regmap, pwrc->base + RTC_BBPU, RTC_BBPU_KEY); regmap_write(pwrc->regmap, pwrc->base + RTC_BBPU, RTC_BBPU_KEY);
regmap_write(pwrc->regmap, pwrc->base + RTC_WRTGR, 1); regmap_write(pwrc->regmap, pwrc->base + RTC_WRTGR_MT6323, 1);
ret = regmap_read_poll_timeout(pwrc->regmap, ret = regmap_read_poll_timeout(pwrc->regmap,
pwrc->base + RTC_BBPU, val, pwrc->base + RTC_BBPU, val,
......
...@@ -541,6 +541,16 @@ config CHARGER_MAX8998 ...@@ -541,6 +541,16 @@ config CHARGER_MAX8998
Say Y to enable support for the battery charger control sysfs and Say Y to enable support for the battery charger control sysfs and
platform data of MAX8998/LP3974 PMICs. platform data of MAX8998/LP3974 PMICs.
config CHARGER_MP2629
tristate "Monolithic power system MP2629 Battery charger"
depends on MFD_MP2629
depends on MP2629_ADC
depends on IIO
help
Select this option to enable support for Monolithic power system
Battery charger. This driver provides Battery charger power management
functions on the systems.
config CHARGER_QCOM_SMBB config CHARGER_QCOM_SMBB
tristate "Qualcomm Switch-Mode Battery Charger and Boost" tristate "Qualcomm Switch-Mode Battery Charger and Boost"
depends on MFD_SPMI_PMIC || COMPILE_TEST depends on MFD_SPMI_PMIC || COMPILE_TEST
......
...@@ -75,6 +75,7 @@ obj-$(CONFIG_CHARGER_MAX77650) += max77650-charger.o ...@@ -75,6 +75,7 @@ obj-$(CONFIG_CHARGER_MAX77650) += max77650-charger.o
obj-$(CONFIG_CHARGER_MAX77693) += max77693_charger.o obj-$(CONFIG_CHARGER_MAX77693) += max77693_charger.o
obj-$(CONFIG_CHARGER_MAX8997) += max8997_charger.o obj-$(CONFIG_CHARGER_MAX8997) += max8997_charger.o
obj-$(CONFIG_CHARGER_MAX8998) += max8998_charger.o obj-$(CONFIG_CHARGER_MAX8998) += max8998_charger.o
obj-$(CONFIG_CHARGER_MP2629) += mp2629_charger.o
obj-$(CONFIG_CHARGER_QCOM_SMBB) += qcom_smbb.o obj-$(CONFIG_CHARGER_QCOM_SMBB) += qcom_smbb.o
obj-$(CONFIG_CHARGER_BQ2415X) += bq2415x_charger.o obj-$(CONFIG_CHARGER_BQ2415X) += bq2415x_charger.o
obj-$(CONFIG_CHARGER_BQ24190) += bq24190_charger.o obj-$(CONFIG_CHARGER_BQ24190) += bq24190_charger.o
......
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* MP2629 battery charger driver
*
* Copyright 2020 Monolithic Power Systems, Inc
*
* Author: Saravanan Sekar <sravanhome@gmail.com>
*/
#include <linux/bits.h>
#include <linux/iio/consumer.h>
#include <linux/iio/types.h>
#include <linux/interrupt.h>
#include <linux/mfd/mp2629.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#include <linux/power_supply.h>
#include <linux/regmap.h>
#define MP2629_REG_INPUT_ILIM 0x00
#define MP2629_REG_INPUT_VLIM 0x01
#define MP2629_REG_CHARGE_CTRL 0x04
#define MP2629_REG_CHARGE_ILIM 0x05
#define MP2629_REG_PRECHARGE 0x06
#define MP2629_REG_TERM_CURRENT 0x06
#define MP2629_REG_CHARGE_VLIM 0x07
#define MP2629_REG_TIMER_CTRL 0x08
#define MP2629_REG_IMPEDANCE_COMP 0x09
#define MP2629_REG_INTERRUPT 0x0b
#define MP2629_REG_STATUS 0x0c
#define MP2629_REG_FAULT 0x0d
#define MP2629_MASK_INPUT_TYPE GENMASK(7, 5)
#define MP2629_MASK_CHARGE_TYPE GENMASK(4, 3)
#define MP2629_MASK_CHARGE_CTRL GENMASK(5, 4)
#define MP2629_MASK_WDOG_CTRL GENMASK(5, 4)
#define MP2629_MASK_IMPEDANCE GENMASK(7, 4)
#define MP2629_INPUTSOURCE_CHANGE GENMASK(7, 5)
#define MP2629_CHARGING_CHANGE GENMASK(4, 3)
#define MP2629_FAULT_BATTERY BIT(3)
#define MP2629_FAULT_THERMAL BIT(4)
#define MP2629_FAULT_INPUT BIT(5)
#define MP2629_FAULT_OTG BIT(6)
#define MP2629_MAX_BATT_CAPACITY 100
#define MP2629_PROPS(_idx, _min, _max, _step) \
[_idx] = { \
.min = _min, \
.max = _max, \
.step = _step, \
}
enum mp2629_source_type {
MP2629_SOURCE_TYPE_NO_INPUT,
MP2629_SOURCE_TYPE_NON_STD,
MP2629_SOURCE_TYPE_SDP,
MP2629_SOURCE_TYPE_CDP,
MP2629_SOURCE_TYPE_DCP,
MP2629_SOURCE_TYPE_OTG = 7,
};
enum mp2629_field {
INPUT_ILIM,
INPUT_VLIM,
CHARGE_ILIM,
CHARGE_VLIM,
PRECHARGE,
TERM_CURRENT,
MP2629_MAX_FIELD
};
struct mp2629_charger {
struct device *dev;
int status;
int fault;
struct regmap *regmap;
struct regmap_field *regmap_fields[MP2629_MAX_FIELD];
struct mutex lock;
struct power_supply *usb;
struct power_supply *battery;
struct iio_channel *iiochan[MP2629_ADC_CHAN_END];
};
struct mp2629_prop {
int reg;
int mask;
int min;
int max;
int step;
int shift;
};
static enum power_supply_usb_type mp2629_usb_types[] = {
POWER_SUPPLY_USB_TYPE_SDP,
POWER_SUPPLY_USB_TYPE_DCP,
POWER_SUPPLY_USB_TYPE_CDP,
POWER_SUPPLY_USB_TYPE_PD_DRP,
POWER_SUPPLY_USB_TYPE_UNKNOWN
};
static enum power_supply_property mp2629_charger_usb_props[] = {
POWER_SUPPLY_PROP_ONLINE,
POWER_SUPPLY_PROP_USB_TYPE,
POWER_SUPPLY_PROP_VOLTAGE_NOW,
POWER_SUPPLY_PROP_CURRENT_NOW,
POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT,
POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT,
};
static enum power_supply_property mp2629_charger_bat_props[] = {
POWER_SUPPLY_PROP_STATUS,
POWER_SUPPLY_PROP_HEALTH,
POWER_SUPPLY_PROP_CHARGE_TYPE,
POWER_SUPPLY_PROP_VOLTAGE_NOW,
POWER_SUPPLY_PROP_CURRENT_NOW,
POWER_SUPPLY_PROP_CAPACITY,
POWER_SUPPLY_PROP_PRECHARGE_CURRENT,
POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT,
POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX,
};
static struct mp2629_prop props[] = {
MP2629_PROPS(INPUT_ILIM, 100000, 3250000, 50000),
MP2629_PROPS(INPUT_VLIM, 3800000, 5300000, 100000),
MP2629_PROPS(CHARGE_ILIM, 320000, 4520000, 40000),
MP2629_PROPS(CHARGE_VLIM, 3400000, 4670000, 10000),
MP2629_PROPS(PRECHARGE, 120000, 720000, 40000),
MP2629_PROPS(TERM_CURRENT, 80000, 680000, 40000),
};
static const struct reg_field mp2629_reg_fields[] = {
[INPUT_ILIM] = REG_FIELD(MP2629_REG_INPUT_ILIM, 0, 5),
[INPUT_VLIM] = REG_FIELD(MP2629_REG_INPUT_VLIM, 0, 3),
[CHARGE_ILIM] = REG_FIELD(MP2629_REG_CHARGE_ILIM, 0, 6),
[CHARGE_VLIM] = REG_FIELD(MP2629_REG_CHARGE_VLIM, 1, 7),
[PRECHARGE] = REG_FIELD(MP2629_REG_PRECHARGE, 4, 7),
[TERM_CURRENT] = REG_FIELD(MP2629_REG_TERM_CURRENT, 0, 3),
};
static char *adc_chan_name[] = {
"mp2629-batt-volt",
"mp2629-system-volt",
"mp2629-input-volt",
"mp2629-batt-current",
"mp2629-input-current",
};
static int mp2629_read_adc(struct mp2629_charger *charger,
enum mp2629_adc_chan ch,
union power_supply_propval *val)
{
int ret;
int chval;
ret = iio_read_channel_processed(charger->iiochan[ch], &chval);
if (ret)
return ret;
val->intval = chval * 1000;
return 0;
}
static int mp2629_get_prop(struct mp2629_charger *charger,
enum mp2629_field fld,
union power_supply_propval *val)
{
int ret;
unsigned int rval;
ret = regmap_field_read(charger->regmap_fields[fld], &rval);
if (ret)
return ret;
val->intval = rval * props[fld].step + props[fld].min;
return 0;
}
static int mp2629_set_prop(struct mp2629_charger *charger,
enum mp2629_field fld,
const union power_supply_propval *val)
{
unsigned int rval;
if (val->intval < props[fld].min || val->intval > props[fld].max)
return -EINVAL;
rval = (val->intval - props[fld].min) / props[fld].step;
return regmap_field_write(charger->regmap_fields[fld], rval);
}
static int mp2629_get_battery_capacity(struct mp2629_charger *charger,
union power_supply_propval *val)
{
union power_supply_propval vnow, vlim;
int ret;
ret = mp2629_read_adc(charger, MP2629_BATT_VOLT, &vnow);
if (ret)
return ret;
ret = mp2629_get_prop(charger, CHARGE_VLIM, &vlim);
if (ret)
return ret;
val->intval = (vnow.intval * 100) / vlim.intval;
val->intval = min(val->intval, MP2629_MAX_BATT_CAPACITY);
return 0;
}
static int mp2629_charger_battery_get_prop(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
{
struct mp2629_charger *charger = dev_get_drvdata(psy->dev.parent);
unsigned int rval;
int ret = 0;
switch (psp) {
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
ret = mp2629_read_adc(charger, MP2629_BATT_VOLT, val);
break;
case POWER_SUPPLY_PROP_CURRENT_NOW:
ret = mp2629_read_adc(charger, MP2629_BATT_CURRENT, val);
break;
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
val->intval = 4520000;
break;
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
val->intval = 4670000;
break;
case POWER_SUPPLY_PROP_CAPACITY:
ret = mp2629_get_battery_capacity(charger, val);
break;
case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
ret = mp2629_get_prop(charger, TERM_CURRENT, val);
break;
case POWER_SUPPLY_PROP_PRECHARGE_CURRENT:
ret = mp2629_get_prop(charger, PRECHARGE, val);
break;
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
ret = mp2629_get_prop(charger, CHARGE_VLIM, val);
break;
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
ret = mp2629_get_prop(charger, CHARGE_ILIM, val);
break;
case POWER_SUPPLY_PROP_HEALTH:
if (!charger->fault)
val->intval = POWER_SUPPLY_HEALTH_GOOD;
if (MP2629_FAULT_BATTERY & charger->fault)
val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
else if (MP2629_FAULT_THERMAL & charger->fault)
val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
else if (MP2629_FAULT_INPUT & charger->fault)
val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
break;
case POWER_SUPPLY_PROP_STATUS:
ret = regmap_read(charger->regmap, MP2629_REG_STATUS, &rval);
if (ret)
break;
rval = (rval & MP2629_MASK_CHARGE_TYPE) >> 3;
switch (rval) {
case 0x00:
val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
break;
case 0x01:
case 0x10:
val->intval = POWER_SUPPLY_STATUS_CHARGING;
break;
case 0x11:
val->intval = POWER_SUPPLY_STATUS_FULL;
}
break;
case POWER_SUPPLY_PROP_CHARGE_TYPE:
ret = regmap_read(charger->regmap, MP2629_REG_STATUS, &rval);
if (ret)
break;
rval = (rval & MP2629_MASK_CHARGE_TYPE) >> 3;
switch (rval) {
case 0x00:
val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
break;
case 0x01:
val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
break;
case 0x10:
val->intval = POWER_SUPPLY_CHARGE_TYPE_STANDARD;
break;
default:
val->intval = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN;
}
break;
default:
return -EINVAL;
}
return ret;
}
static int mp2629_charger_battery_set_prop(struct power_supply *psy,
enum power_supply_property psp,
const union power_supply_propval *val)
{
struct mp2629_charger *charger = dev_get_drvdata(psy->dev.parent);
switch (psp) {
case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
return mp2629_set_prop(charger, TERM_CURRENT, val);
case POWER_SUPPLY_PROP_PRECHARGE_CURRENT:
return mp2629_set_prop(charger, PRECHARGE, val);
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
return mp2629_set_prop(charger, CHARGE_VLIM, val);
case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
return mp2629_set_prop(charger, CHARGE_ILIM, val);
default:
return -EINVAL;
}
}
static int mp2629_charger_usb_get_prop(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
{
struct mp2629_charger *charger = dev_get_drvdata(psy->dev.parent);
unsigned int rval;
int ret;
switch (psp) {
case POWER_SUPPLY_PROP_ONLINE:
ret = regmap_read(charger->regmap, MP2629_REG_STATUS, &rval);
if (ret)
break;
val->intval = !!(rval & MP2629_MASK_INPUT_TYPE);
break;
case POWER_SUPPLY_PROP_USB_TYPE:
ret = regmap_read(charger->regmap, MP2629_REG_STATUS, &rval);
if (ret)
break;
rval = (rval & MP2629_MASK_INPUT_TYPE) >> 5;
switch (rval) {
case MP2629_SOURCE_TYPE_SDP:
val->intval = POWER_SUPPLY_USB_TYPE_SDP;
break;
case MP2629_SOURCE_TYPE_CDP:
val->intval = POWER_SUPPLY_USB_TYPE_CDP;
break;
case MP2629_SOURCE_TYPE_DCP:
val->intval = POWER_SUPPLY_USB_TYPE_DCP;
break;
case MP2629_SOURCE_TYPE_OTG:
val->intval = POWER_SUPPLY_USB_TYPE_PD_DRP;
break;
default:
val->intval = POWER_SUPPLY_USB_TYPE_UNKNOWN;
break;
}
break;
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
ret = mp2629_read_adc(charger, MP2629_INPUT_VOLT, val);
break;
case POWER_SUPPLY_PROP_CURRENT_NOW:
ret = mp2629_read_adc(charger, MP2629_INPUT_CURRENT, val);
break;
case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT:
ret = mp2629_get_prop(charger, INPUT_VLIM, val);
break;
case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
ret = mp2629_get_prop(charger, INPUT_ILIM, val);
break;
default:
return -EINVAL;
}
return ret;
}
static int mp2629_charger_usb_set_prop(struct power_supply *psy,
enum power_supply_property psp,
const union power_supply_propval *val)
{
struct mp2629_charger *charger = dev_get_drvdata(psy->dev.parent);
switch (psp) {
case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT:
return mp2629_set_prop(charger, INPUT_VLIM, val);
case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT:
return mp2629_set_prop(charger, INPUT_ILIM, val);
default:
return -EINVAL;
}
}
static int mp2629_charger_battery_prop_writeable(struct power_supply *psy,
enum power_supply_property psp)
{
return (psp == POWER_SUPPLY_PROP_PRECHARGE_CURRENT) ||
(psp == POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT) ||
(psp == POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT) ||
(psp == POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE);
}
static int mp2629_charger_usb_prop_writeable(struct power_supply *psy,
enum power_supply_property psp)
{
return (psp == POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT) ||
(psp == POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT);
}
static irqreturn_t mp2629_irq_handler(int irq, void *dev_id)
{
struct mp2629_charger *charger = dev_id;
unsigned int rval;
int ret;
mutex_lock(&charger->lock);
ret = regmap_read(charger->regmap, MP2629_REG_FAULT, &rval);
if (ret)
goto unlock;
if (rval) {
charger->fault = rval;
if (MP2629_FAULT_BATTERY & rval)
dev_err(charger->dev, "Battery fault OVP\n");
else if (MP2629_FAULT_THERMAL & rval)
dev_err(charger->dev, "Thermal shutdown fault\n");
else if (MP2629_FAULT_INPUT & rval)
dev_err(charger->dev, "no input or input OVP\n");
else if (MP2629_FAULT_OTG & rval)
dev_err(charger->dev, "VIN overloaded\n");
goto unlock;
}
ret = regmap_read(charger->regmap, MP2629_REG_STATUS, &rval);
if (ret)
goto unlock;
if (rval & MP2629_INPUTSOURCE_CHANGE)
power_supply_changed(charger->usb);
else if (rval & MP2629_CHARGING_CHANGE)
power_supply_changed(charger->battery);
unlock:
mutex_unlock(&charger->lock);
return IRQ_HANDLED;
}
static const struct power_supply_desc mp2629_usb_desc = {
.name = "mp2629_usb",
.type = POWER_SUPPLY_TYPE_USB,
.usb_types = mp2629_usb_types,
.num_usb_types = ARRAY_SIZE(mp2629_usb_types),
.properties = mp2629_charger_usb_props,
.num_properties = ARRAY_SIZE(mp2629_charger_usb_props),
.get_property = mp2629_charger_usb_get_prop,
.set_property = mp2629_charger_usb_set_prop,
.property_is_writeable = mp2629_charger_usb_prop_writeable,
};
static const struct power_supply_desc mp2629_battery_desc = {
.name = "mp2629_battery",
.type = POWER_SUPPLY_TYPE_BATTERY,
.properties = mp2629_charger_bat_props,
.num_properties = ARRAY_SIZE(mp2629_charger_bat_props),
.get_property = mp2629_charger_battery_get_prop,
.set_property = mp2629_charger_battery_set_prop,
.property_is_writeable = mp2629_charger_battery_prop_writeable,
};
static ssize_t batt_impedance_compensation_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct mp2629_charger *charger = dev_get_drvdata(dev->parent);
unsigned int rval;
int ret;
ret = regmap_read(charger->regmap, MP2629_REG_IMPEDANCE_COMP, &rval);
if (ret)
return ret;
rval = (rval >> 4) * 10;
return sprintf(buf, "%d mohm\n", rval);
}
static ssize_t batt_impedance_compensation_store(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t count)
{
struct mp2629_charger *charger = dev_get_drvdata(dev->parent);
unsigned int val;
int ret;
ret = kstrtouint(buf, 10, &val);
if (ret)
return ret;
if (val > 140)
return -ERANGE;
/* multiples of 10 mohm so round off */
val = val / 10;
ret = regmap_update_bits(charger->regmap, MP2629_REG_IMPEDANCE_COMP,
MP2629_MASK_IMPEDANCE, val << 4);
if (ret)
return ret;
return count;
}
static DEVICE_ATTR_RW(batt_impedance_compensation);
static struct attribute *mp2629_charger_sysfs_attrs[] = {
&dev_attr_batt_impedance_compensation.attr,
NULL
};
ATTRIBUTE_GROUPS(mp2629_charger_sysfs);
static void mp2629_charger_disable(void *data)
{
struct mp2629_charger *charger = data;
regmap_update_bits(charger->regmap, MP2629_REG_CHARGE_CTRL,
MP2629_MASK_CHARGE_CTRL, 0);
}
static int mp2629_charger_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct mp2629_data *ddata = dev_get_drvdata(dev->parent);
struct mp2629_charger *charger;
struct power_supply_config psy_cfg = {};
int ret, i, irq;
charger = devm_kzalloc(dev, sizeof(*charger), GFP_KERNEL);
if (!charger)
return -ENOMEM;
charger->regmap = ddata->regmap;
charger->dev = dev;
platform_set_drvdata(pdev, charger);
irq = platform_get_irq_optional(to_platform_device(dev->parent), 0);
if (irq < 0) {
dev_err(dev, "get irq fail: %d\n", irq);
return irq;
}
for (i = 0; i < MP2629_MAX_FIELD; i++) {
charger->regmap_fields[i] = devm_regmap_field_alloc(dev,
charger->regmap, mp2629_reg_fields[i]);
if (IS_ERR(charger->regmap_fields[i])) {
dev_err(dev, "regmap field alloc fail %d\n", i);
return PTR_ERR(charger->regmap_fields[i]);
}
}
for (i = 0; i < MP2629_ADC_CHAN_END; i++) {
charger->iiochan[i] = devm_iio_channel_get(dev,
adc_chan_name[i]);
if (IS_ERR(charger->iiochan[i])) {
dev_err(dev, "iio chan get %s err\n", adc_chan_name[i]);
return PTR_ERR(charger->iiochan[i]);
}
}
ret = devm_add_action_or_reset(dev, mp2629_charger_disable, charger);
if (ret)
return ret;
charger->usb = devm_power_supply_register(dev, &mp2629_usb_desc, NULL);
if (IS_ERR(charger->usb)) {
dev_err(dev, "power supply register usb failed\n");
return PTR_ERR(charger->usb);
}
psy_cfg.drv_data = charger;
psy_cfg.attr_grp = mp2629_charger_sysfs_groups;
charger->battery = devm_power_supply_register(dev,
&mp2629_battery_desc, &psy_cfg);
if (IS_ERR(charger->battery)) {
dev_err(dev, "power supply register battery failed\n");
return PTR_ERR(charger->battery);
}
ret = regmap_update_bits(charger->regmap, MP2629_REG_CHARGE_CTRL,
MP2629_MASK_CHARGE_CTRL, BIT(4));
if (ret) {
dev_err(dev, "enable charge fail: %d\n", ret);
return ret;
}
regmap_update_bits(charger->regmap, MP2629_REG_TIMER_CTRL,
MP2629_MASK_WDOG_CTRL, 0);
mutex_init(&charger->lock);
ret = devm_request_threaded_irq(dev, irq, NULL, mp2629_irq_handler,
IRQF_ONESHOT | IRQF_TRIGGER_RISING,
"mp2629-charger", charger);
if (ret) {
dev_err(dev, "failed to request gpio IRQ\n");
return ret;
}
regmap_update_bits(charger->regmap, MP2629_REG_INTERRUPT,
GENMASK(6, 5), BIT(6) | BIT(5));
return 0;
}
static const struct of_device_id mp2629_charger_of_match[] = {
{ .compatible = "mps,mp2629_charger"},
{}
};
MODULE_DEVICE_TABLE(of, mp2629_charger_of_match);
static struct platform_driver mp2629_charger_driver = {
.driver = {
.name = "mp2629_charger",
.of_match_table = mp2629_charger_of_match,
},
.probe = mp2629_charger_probe,
};
module_platform_driver(mp2629_charger_driver);
MODULE_AUTHOR("Saravanan Sekar <sravanhome@gmail.com>");
MODULE_DESCRIPTION("MP2629 Charger driver");
MODULE_LICENSE("GPL");
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <linux/mfd/mt6397/core.h> #include <linux/mfd/mt6397/core.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/of_device.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/rtc.h> #include <linux/rtc.h>
...@@ -20,7 +21,7 @@ static int mtk_rtc_write_trigger(struct mt6397_rtc *rtc) ...@@ -20,7 +21,7 @@ static int mtk_rtc_write_trigger(struct mt6397_rtc *rtc)
int ret; int ret;
u32 data; u32 data;
ret = regmap_write(rtc->regmap, rtc->addr_base + RTC_WRTGR, 1); ret = regmap_write(rtc->regmap, rtc->addr_base + rtc->data->wrtgr, 1);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -269,6 +270,8 @@ static int mtk_rtc_probe(struct platform_device *pdev) ...@@ -269,6 +270,8 @@ static int mtk_rtc_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
rtc->addr_base = res->start; rtc->addr_base = res->start;
rtc->data = of_device_get_match_data(&pdev->dev);
rtc->irq = platform_get_irq(pdev, 0); rtc->irq = platform_get_irq(pdev, 0);
if (rtc->irq < 0) if (rtc->irq < 0)
return rtc->irq; return rtc->irq;
...@@ -325,9 +328,18 @@ static int mt6397_rtc_resume(struct device *dev) ...@@ -325,9 +328,18 @@ static int mt6397_rtc_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(mt6397_pm_ops, mt6397_rtc_suspend, static SIMPLE_DEV_PM_OPS(mt6397_pm_ops, mt6397_rtc_suspend,
mt6397_rtc_resume); mt6397_rtc_resume);
static const struct mtk_rtc_data mt6358_rtc_data = {
.wrtgr = RTC_WRTGR_MT6358,
};
static const struct mtk_rtc_data mt6397_rtc_data = {
.wrtgr = RTC_WRTGR_MT6397,
};
static const struct of_device_id mt6397_rtc_of_match[] = { static const struct of_device_id mt6397_rtc_of_match[] = {
{ .compatible = "mediatek,mt6323-rtc", }, { .compatible = "mediatek,mt6323-rtc", .data = &mt6397_rtc_data },
{ .compatible = "mediatek,mt6397-rtc", }, { .compatible = "mediatek,mt6358-rtc", .data = &mt6358_rtc_data },
{ .compatible = "mediatek,mt6397-rtc", .data = &mt6397_rtc_data },
{ } { }
}; };
MODULE_DEVICE_TABLE(of, mt6397_rtc_of_match); MODULE_DEVICE_TABLE(of, mt6397_rtc_of_match);
......
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2020 Gateworks Corporation
*/
#ifndef __LINUX_MFD_GSC_H_
#define __LINUX_MFD_GSC_H_
#include <linux/regmap.h>
/* Device Addresses */
#define GSC_MISC 0x20
#define GSC_UPDATE 0x21
#define GSC_GPIO 0x23
#define GSC_HWMON 0x29
#define GSC_EEPROM0 0x50
#define GSC_EEPROM1 0x51
#define GSC_EEPROM2 0x52
#define GSC_EEPROM3 0x53
#define GSC_RTC 0x68
/* Register offsets */
enum {
GSC_CTRL_0 = 0x00,
GSC_CTRL_1 = 0x01,
GSC_TIME = 0x02,
GSC_TIME_ADD = 0x06,
GSC_IRQ_STATUS = 0x0A,
GSC_IRQ_ENABLE = 0x0B,
GSC_FW_CRC = 0x0C,
GSC_FW_VER = 0x0E,
GSC_WP = 0x0F,
};
/* Bit definitions */
#define GSC_CTRL_0_PB_HARD_RESET 0
#define GSC_CTRL_0_PB_CLEAR_SECURE_KEY 1
#define GSC_CTRL_0_PB_SOFT_POWER_DOWN 2
#define GSC_CTRL_0_PB_BOOT_ALTERNATE 3
#define GSC_CTRL_0_PERFORM_CRC 4
#define GSC_CTRL_0_TAMPER_DETECT 5
#define GSC_CTRL_0_SWITCH_HOLD 6
#define GSC_CTRL_1_SLEEP_ENABLE 0
#define GSC_CTRL_1_SLEEP_ACTIVATE 1
#define GSC_CTRL_1_SLEEP_ADD 2
#define GSC_CTRL_1_SLEEP_NOWAKEPB 3
#define GSC_CTRL_1_WDT_TIME 4
#define GSC_CTRL_1_WDT_ENABLE 5
#define GSC_CTRL_1_SWITCH_BOOT_ENABLE 6
#define GSC_CTRL_1_SWITCH_BOOT_CLEAR 7
#define GSC_IRQ_PB 0
#define GSC_IRQ_KEY_ERASED 1
#define GSC_IRQ_EEPROM_WP 2
#define GSC_IRQ_RESV 3
#define GSC_IRQ_GPIO 4
#define GSC_IRQ_TAMPER 5
#define GSC_IRQ_WDT_TIMEOUT 6
#define GSC_IRQ_SWITCH_HOLD 7
int gsc_read(void *context, unsigned int reg, unsigned int *val);
int gsc_write(void *context, unsigned int reg, unsigned int val);
struct gsc_dev {
struct device *dev;
struct i2c_client *i2c; /* 0x20: interrupt controller, WDT */
struct i2c_client *i2c_hwmon; /* 0x29: hwmon, fan controller */
struct regmap *regmap;
unsigned int fwver;
unsigned short fwcrc;
};
#endif /* __LINUX_MFD_GSC_H_ */
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright 2020 Monolithic Power Systems, Inc
*/
#ifndef __MP2629_H__
#define __MP2629_H__
#include <linux/device.h>
#include <linux/regmap.h>
struct mp2629_data {
struct device *dev;
struct regmap *regmap;
};
enum mp2629_adc_chan {
MP2629_BATT_VOLT,
MP2629_SYSTEM_VOLT,
MP2629_INPUT_VOLT,
MP2629_BATT_CURRENT,
MP2629_INPUT_CURRENT,
MP2629_ADC_CHAN_END
};
#endif
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2020 MediaTek Inc.
*/
#ifndef __MFD_MT6358_CORE_H__
#define __MFD_MT6358_CORE_H__
#define MT6358_REG_WIDTH 16
struct irq_top_t {
int hwirq_base;
unsigned int num_int_regs;
unsigned int num_int_bits;
unsigned int en_reg;
unsigned int en_reg_shift;
unsigned int sta_reg;
unsigned int sta_reg_shift;
unsigned int top_offset;
};
struct pmic_irq_data {
unsigned int num_top;
unsigned int num_pmic_irqs;
unsigned short top_int_status_reg;
bool *enable_hwirq;
bool *cache_hwirq;
};
enum mt6358_irq_top_status_shift {
MT6358_BUCK_TOP = 0,
MT6358_LDO_TOP,
MT6358_PSC_TOP,
MT6358_SCK_TOP,
MT6358_BM_TOP,
MT6358_HK_TOP,
MT6358_AUD_TOP,
MT6358_MISC_TOP,
};
enum mt6358_irq_numbers {
MT6358_IRQ_VPROC11_OC = 0,
MT6358_IRQ_VPROC12_OC,
MT6358_IRQ_VCORE_OC,
MT6358_IRQ_VGPU_OC,
MT6358_IRQ_VMODEM_OC,
MT6358_IRQ_VDRAM1_OC,
MT6358_IRQ_VS1_OC,
MT6358_IRQ_VS2_OC,
MT6358_IRQ_VPA_OC,
MT6358_IRQ_VCORE_PREOC,
MT6358_IRQ_VFE28_OC = 16,
MT6358_IRQ_VXO22_OC,
MT6358_IRQ_VRF18_OC,
MT6358_IRQ_VRF12_OC,
MT6358_IRQ_VEFUSE_OC,
MT6358_IRQ_VCN33_OC,
MT6358_IRQ_VCN28_OC,
MT6358_IRQ_VCN18_OC,
MT6358_IRQ_VCAMA1_OC,
MT6358_IRQ_VCAMA2_OC,
MT6358_IRQ_VCAMD_OC,
MT6358_IRQ_VCAMIO_OC,
MT6358_IRQ_VLDO28_OC,
MT6358_IRQ_VA12_OC,
MT6358_IRQ_VAUX18_OC,
MT6358_IRQ_VAUD28_OC,
MT6358_IRQ_VIO28_OC,
MT6358_IRQ_VIO18_OC,
MT6358_IRQ_VSRAM_PROC11_OC,
MT6358_IRQ_VSRAM_PROC12_OC,
MT6358_IRQ_VSRAM_OTHERS_OC,
MT6358_IRQ_VSRAM_GPU_OC,
MT6358_IRQ_VDRAM2_OC,
MT6358_IRQ_VMC_OC,
MT6358_IRQ_VMCH_OC,
MT6358_IRQ_VEMC_OC,
MT6358_IRQ_VSIM1_OC,
MT6358_IRQ_VSIM2_OC,
MT6358_IRQ_VIBR_OC,
MT6358_IRQ_VUSB_OC,
MT6358_IRQ_VBIF28_OC,
MT6358_IRQ_PWRKEY = 48,
MT6358_IRQ_HOMEKEY,
MT6358_IRQ_PWRKEY_R,
MT6358_IRQ_HOMEKEY_R,
MT6358_IRQ_NI_LBAT_INT,
MT6358_IRQ_CHRDET,
MT6358_IRQ_CHRDET_EDGE,
MT6358_IRQ_VCDT_HV_DET,
MT6358_IRQ_RTC = 64,
MT6358_IRQ_FG_BAT0_H = 80,
MT6358_IRQ_FG_BAT0_L,
MT6358_IRQ_FG_CUR_H,
MT6358_IRQ_FG_CUR_L,
MT6358_IRQ_FG_ZCV,
MT6358_IRQ_FG_BAT1_H,
MT6358_IRQ_FG_BAT1_L,
MT6358_IRQ_FG_N_CHARGE_L,
MT6358_IRQ_FG_IAVG_H,
MT6358_IRQ_FG_IAVG_L,
MT6358_IRQ_FG_TIME_H,
MT6358_IRQ_FG_DISCHARGE,
MT6358_IRQ_FG_CHARGE,
MT6358_IRQ_BATON_LV = 96,
MT6358_IRQ_BATON_HT,
MT6358_IRQ_BATON_BAT_IN,
MT6358_IRQ_BATON_BAT_OUT,
MT6358_IRQ_BIF,
MT6358_IRQ_BAT_H = 112,
MT6358_IRQ_BAT_L,
MT6358_IRQ_BAT2_H,
MT6358_IRQ_BAT2_L,
MT6358_IRQ_BAT_TEMP_H,
MT6358_IRQ_BAT_TEMP_L,
MT6358_IRQ_AUXADC_IMP,
MT6358_IRQ_NAG_C_DLTV,
MT6358_IRQ_AUDIO = 128,
MT6358_IRQ_ACCDET = 133,
MT6358_IRQ_ACCDET_EINT0,
MT6358_IRQ_ACCDET_EINT1,
MT6358_IRQ_SPI_CMD_ALERT = 144,
MT6358_IRQ_NR,
};
#define MT6358_IRQ_BUCK_BASE MT6358_IRQ_VPROC11_OC
#define MT6358_IRQ_LDO_BASE MT6358_IRQ_VFE28_OC
#define MT6358_IRQ_PSC_BASE MT6358_IRQ_PWRKEY
#define MT6358_IRQ_SCK_BASE MT6358_IRQ_RTC
#define MT6358_IRQ_BM_BASE MT6358_IRQ_FG_BAT0_H
#define MT6358_IRQ_HK_BASE MT6358_IRQ_BAT_H
#define MT6358_IRQ_AUD_BASE MT6358_IRQ_AUDIO
#define MT6358_IRQ_MISC_BASE MT6358_IRQ_SPI_CMD_ALERT
#define MT6358_IRQ_BUCK_BITS (MT6358_IRQ_VCORE_PREOC - MT6358_IRQ_BUCK_BASE + 1)
#define MT6358_IRQ_LDO_BITS (MT6358_IRQ_VBIF28_OC - MT6358_IRQ_LDO_BASE + 1)
#define MT6358_IRQ_PSC_BITS (MT6358_IRQ_VCDT_HV_DET - MT6358_IRQ_PSC_BASE + 1)
#define MT6358_IRQ_SCK_BITS (MT6358_IRQ_RTC - MT6358_IRQ_SCK_BASE + 1)
#define MT6358_IRQ_BM_BITS (MT6358_IRQ_BIF - MT6358_IRQ_BM_BASE + 1)
#define MT6358_IRQ_HK_BITS (MT6358_IRQ_NAG_C_DLTV - MT6358_IRQ_HK_BASE + 1)
#define MT6358_IRQ_AUD_BITS (MT6358_IRQ_ACCDET_EINT1 - MT6358_IRQ_AUD_BASE + 1)
#define MT6358_IRQ_MISC_BITS \
(MT6358_IRQ_SPI_CMD_ALERT - MT6358_IRQ_MISC_BASE + 1)
#define MT6358_TOP_GEN(sp) \
{ \
.hwirq_base = MT6358_IRQ_##sp##_BASE, \
.num_int_regs = \
((MT6358_IRQ_##sp##_BITS - 1) / MT6358_REG_WIDTH) + 1, \
.num_int_bits = MT6358_IRQ_##sp##_BITS, \
.en_reg = MT6358_##sp##_TOP_INT_CON0, \
.en_reg_shift = 0x6, \
.sta_reg = MT6358_##sp##_TOP_INT_STATUS0, \
.sta_reg_shift = 0x2, \
.top_offset = MT6358_##sp##_TOP, \
}
#endif /* __MFD_MT6358_CORE_H__ */
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2020 MediaTek Inc.
*/
#ifndef __MFD_MT6358_REGISTERS_H__
#define __MFD_MT6358_REGISTERS_H__
/* PMIC Registers */
#define MT6358_SWCID 0xa
#define MT6358_MISC_TOP_INT_CON0 0x188
#define MT6358_MISC_TOP_INT_STATUS0 0x194
#define MT6358_TOP_INT_STATUS0 0x19e
#define MT6358_SCK_TOP_INT_CON0 0x52e
#define MT6358_SCK_TOP_INT_STATUS0 0x53a
#define MT6358_EOSC_CALI_CON0 0x540
#define MT6358_EOSC_CALI_CON1 0x542
#define MT6358_RTC_MIX_CON0 0x544
#define MT6358_RTC_MIX_CON1 0x546
#define MT6358_RTC_MIX_CON2 0x548
#define MT6358_RTC_DSN_ID 0x580
#define MT6358_RTC_DSN_REV0 0x582
#define MT6358_RTC_DBI 0x584
#define MT6358_RTC_DXI 0x586
#define MT6358_RTC_BBPU 0x588
#define MT6358_RTC_IRQ_STA 0x58a
#define MT6358_RTC_IRQ_EN 0x58c
#define MT6358_RTC_CII_EN 0x58e
#define MT6358_RTC_AL_MASK 0x590
#define MT6358_RTC_TC_SEC 0x592
#define MT6358_RTC_TC_MIN 0x594
#define MT6358_RTC_TC_HOU 0x596
#define MT6358_RTC_TC_DOM 0x598
#define MT6358_RTC_TC_DOW 0x59a
#define MT6358_RTC_TC_MTH 0x59c
#define MT6358_RTC_TC_YEA 0x59e
#define MT6358_RTC_AL_SEC 0x5a0
#define MT6358_RTC_AL_MIN 0x5a2
#define MT6358_RTC_AL_HOU 0x5a4
#define MT6358_RTC_AL_DOM 0x5a6
#define MT6358_RTC_AL_DOW 0x5a8
#define MT6358_RTC_AL_MTH 0x5aa
#define MT6358_RTC_AL_YEA 0x5ac
#define MT6358_RTC_OSC32CON 0x5ae
#define MT6358_RTC_POWERKEY1 0x5b0
#define MT6358_RTC_POWERKEY2 0x5b2
#define MT6358_RTC_PDN1 0x5b4
#define MT6358_RTC_PDN2 0x5b6
#define MT6358_RTC_SPAR0 0x5b8
#define MT6358_RTC_SPAR1 0x5ba
#define MT6358_RTC_PROT 0x5bc
#define MT6358_RTC_DIFF 0x5be
#define MT6358_RTC_CALI 0x5c0
#define MT6358_RTC_WRTGR 0x5c2
#define MT6358_RTC_CON 0x5c4
#define MT6358_RTC_SEC_CTRL 0x5c6
#define MT6358_RTC_INT_CNT 0x5c8
#define MT6358_RTC_SEC_DAT0 0x5ca
#define MT6358_RTC_SEC_DAT1 0x5cc
#define MT6358_RTC_SEC_DAT2 0x5ce
#define MT6358_RTC_SEC_DSN_ID 0x600
#define MT6358_RTC_SEC_DSN_REV0 0x602
#define MT6358_RTC_SEC_DBI 0x604
#define MT6358_RTC_SEC_DXI 0x606
#define MT6358_RTC_TC_SEC_SEC 0x608
#define MT6358_RTC_TC_MIN_SEC 0x60a
#define MT6358_RTC_TC_HOU_SEC 0x60c
#define MT6358_RTC_TC_DOM_SEC 0x60e
#define MT6358_RTC_TC_DOW_SEC 0x610
#define MT6358_RTC_TC_MTH_SEC 0x612
#define MT6358_RTC_TC_YEA_SEC 0x614
#define MT6358_RTC_SEC_CK_PDN 0x616
#define MT6358_RTC_SEC_WRTGR 0x618
#define MT6358_PSC_TOP_INT_CON0 0x910
#define MT6358_PSC_TOP_INT_STATUS0 0x91c
#define MT6358_BM_TOP_INT_CON0 0xc32
#define MT6358_BM_TOP_INT_CON1 0xc38
#define MT6358_BM_TOP_INT_STATUS0 0xc4a
#define MT6358_BM_TOP_INT_STATUS1 0xc4c
#define MT6358_HK_TOP_INT_CON0 0xf92
#define MT6358_HK_TOP_INT_STATUS0 0xf9e
#define MT6358_BUCK_TOP_INT_CON0 0x1318
#define MT6358_BUCK_TOP_INT_STATUS0 0x1324
#define MT6358_BUCK_VPROC11_CON0 0x1388
#define MT6358_BUCK_VPROC11_DBG0 0x139e
#define MT6358_BUCK_VPROC11_DBG1 0x13a0
#define MT6358_BUCK_VPROC11_ELR0 0x13a6
#define MT6358_BUCK_VPROC12_CON0 0x1408
#define MT6358_BUCK_VPROC12_DBG0 0x141e
#define MT6358_BUCK_VPROC12_DBG1 0x1420
#define MT6358_BUCK_VPROC12_ELR0 0x1426
#define MT6358_BUCK_VCORE_CON0 0x1488
#define MT6358_BUCK_VCORE_DBG0 0x149e
#define MT6358_BUCK_VCORE_DBG1 0x14a0
#define MT6358_BUCK_VCORE_ELR0 0x14aa
#define MT6358_BUCK_VGPU_CON0 0x1508
#define MT6358_BUCK_VGPU_DBG0 0x151e
#define MT6358_BUCK_VGPU_DBG1 0x1520
#define MT6358_BUCK_VGPU_ELR0 0x1526
#define MT6358_BUCK_VMODEM_CON0 0x1588
#define MT6358_BUCK_VMODEM_DBG0 0x159e
#define MT6358_BUCK_VMODEM_DBG1 0x15a0
#define MT6358_BUCK_VMODEM_ELR0 0x15a6
#define MT6358_BUCK_VDRAM1_CON0 0x1608
#define MT6358_BUCK_VDRAM1_DBG0 0x161e
#define MT6358_BUCK_VDRAM1_DBG1 0x1620
#define MT6358_BUCK_VDRAM1_ELR0 0x1626
#define MT6358_BUCK_VS1_CON0 0x1688
#define MT6358_BUCK_VS1_DBG0 0x169e
#define MT6358_BUCK_VS1_DBG1 0x16a0
#define MT6358_BUCK_VS1_ELR0 0x16ae
#define MT6358_BUCK_VS2_CON0 0x1708
#define MT6358_BUCK_VS2_DBG0 0x171e
#define MT6358_BUCK_VS2_DBG1 0x1720
#define MT6358_BUCK_VS2_ELR0 0x172e
#define MT6358_BUCK_VPA_CON0 0x1788
#define MT6358_BUCK_VPA_CON1 0x178a
#define MT6358_BUCK_VPA_ELR0 MT6358_BUCK_VPA_CON1
#define MT6358_BUCK_VPA_DBG0 0x1792
#define MT6358_BUCK_VPA_DBG1 0x1794
#define MT6358_VPROC_ANA_CON0 0x180c
#define MT6358_VCORE_VGPU_ANA_CON0 0x1828
#define MT6358_VMODEM_ANA_CON0 0x1888
#define MT6358_VDRAM1_ANA_CON0 0x1896
#define MT6358_VS1_ANA_CON0 0x18a2
#define MT6358_VS2_ANA_CON0 0x18ae
#define MT6358_VPA_ANA_CON0 0x18ba
#define MT6358_LDO_TOP_INT_CON0 0x1a50
#define MT6358_LDO_TOP_INT_CON1 0x1a56
#define MT6358_LDO_TOP_INT_STATUS0 0x1a68
#define MT6358_LDO_TOP_INT_STATUS1 0x1a6a
#define MT6358_LDO_VXO22_CON0 0x1a88
#define MT6358_LDO_VXO22_CON1 0x1a96
#define MT6358_LDO_VA12_CON0 0x1a9c
#define MT6358_LDO_VA12_CON1 0x1aaa
#define MT6358_LDO_VAUX18_CON0 0x1ab0
#define MT6358_LDO_VAUX18_CON1 0x1abe
#define MT6358_LDO_VAUD28_CON0 0x1ac4
#define MT6358_LDO_VAUD28_CON1 0x1ad2
#define MT6358_LDO_VIO28_CON0 0x1ad8
#define MT6358_LDO_VIO28_CON1 0x1ae6
#define MT6358_LDO_VIO18_CON0 0x1aec
#define MT6358_LDO_VIO18_CON1 0x1afa
#define MT6358_LDO_VDRAM2_CON0 0x1b08
#define MT6358_LDO_VDRAM2_CON1 0x1b16
#define MT6358_LDO_VEMC_CON0 0x1b1c
#define MT6358_LDO_VEMC_CON1 0x1b2a
#define MT6358_LDO_VUSB_CON0_0 0x1b30
#define MT6358_LDO_VUSB_CON1 0x1b40
#define MT6358_LDO_VSRAM_PROC11_CON0 0x1b46
#define MT6358_LDO_VSRAM_PROC11_DBG0 0x1b60
#define MT6358_LDO_VSRAM_PROC11_DBG1 0x1b62
#define MT6358_LDO_VSRAM_PROC11_TRACKING_CON0 0x1b64
#define MT6358_LDO_VSRAM_PROC11_TRACKING_CON1 0x1b66
#define MT6358_LDO_VSRAM_PROC11_TRACKING_CON2 0x1b68
#define MT6358_LDO_VSRAM_PROC11_TRACKING_CON3 0x1b6a
#define MT6358_LDO_VSRAM_PROC12_TRACKING_CON0 0x1b6c
#define MT6358_LDO_VSRAM_PROC12_TRACKING_CON1 0x1b6e
#define MT6358_LDO_VSRAM_PROC12_TRACKING_CON2 0x1b70
#define MT6358_LDO_VSRAM_PROC12_TRACKING_CON3 0x1b72
#define MT6358_LDO_VSRAM_WAKEUP_CON0 0x1b74
#define MT6358_LDO_GON1_ELR_NUM 0x1b76
#define MT6358_LDO_VDRAM2_ELR0 0x1b78
#define MT6358_LDO_VSRAM_PROC12_CON0 0x1b88
#define MT6358_LDO_VSRAM_PROC12_DBG0 0x1ba2
#define MT6358_LDO_VSRAM_PROC12_DBG1 0x1ba4
#define MT6358_LDO_VSRAM_OTHERS_CON0 0x1ba6
#define MT6358_LDO_VSRAM_OTHERS_DBG0 0x1bc0
#define MT6358_LDO_VSRAM_OTHERS_DBG1 0x1bc2
#define MT6358_LDO_VSRAM_GPU_CON0 0x1bc8
#define MT6358_LDO_VSRAM_GPU_DBG0 0x1be2
#define MT6358_LDO_VSRAM_GPU_DBG1 0x1be4
#define MT6358_LDO_VSRAM_CON0 0x1bee
#define MT6358_LDO_VSRAM_CON1 0x1bf0
#define MT6358_LDO_VSRAM_CON2 0x1bf2
#define MT6358_LDO_VSRAM_CON3 0x1bf4
#define MT6358_LDO_VFE28_CON0 0x1c08
#define MT6358_LDO_VFE28_CON1 0x1c16
#define MT6358_LDO_VFE28_CON2 0x1c18
#define MT6358_LDO_VFE28_CON3 0x1c1a
#define MT6358_LDO_VRF18_CON0 0x1c1c
#define MT6358_LDO_VRF18_CON1 0x1c2a
#define MT6358_LDO_VRF18_CON2 0x1c2c
#define MT6358_LDO_VRF18_CON3 0x1c2e
#define MT6358_LDO_VRF12_CON0 0x1c30
#define MT6358_LDO_VRF12_CON1 0x1c3e
#define MT6358_LDO_VRF12_CON2 0x1c40
#define MT6358_LDO_VRF12_CON3 0x1c42
#define MT6358_LDO_VEFUSE_CON0 0x1c44
#define MT6358_LDO_VEFUSE_CON1 0x1c52
#define MT6358_LDO_VEFUSE_CON2 0x1c54
#define MT6358_LDO_VEFUSE_CON3 0x1c56
#define MT6358_LDO_VCN18_CON0 0x1c58
#define MT6358_LDO_VCN18_CON1 0x1c66
#define MT6358_LDO_VCN18_CON2 0x1c68
#define MT6358_LDO_VCN18_CON3 0x1c6a
#define MT6358_LDO_VCAMA1_CON0 0x1c6c
#define MT6358_LDO_VCAMA1_CON1 0x1c7a
#define MT6358_LDO_VCAMA1_CON2 0x1c7c
#define MT6358_LDO_VCAMA1_CON3 0x1c7e
#define MT6358_LDO_VCAMA2_CON0 0x1c88
#define MT6358_LDO_VCAMA2_CON1 0x1c96
#define MT6358_LDO_VCAMA2_CON2 0x1c98
#define MT6358_LDO_VCAMA2_CON3 0x1c9a
#define MT6358_LDO_VCAMD_CON0 0x1c9c
#define MT6358_LDO_VCAMD_CON1 0x1caa
#define MT6358_LDO_VCAMD_CON2 0x1cac
#define MT6358_LDO_VCAMD_CON3 0x1cae
#define MT6358_LDO_VCAMIO_CON0 0x1cb0
#define MT6358_LDO_VCAMIO_CON1 0x1cbe
#define MT6358_LDO_VCAMIO_CON2 0x1cc0
#define MT6358_LDO_VCAMIO_CON3 0x1cc2
#define MT6358_LDO_VMC_CON0 0x1cc4
#define MT6358_LDO_VMC_CON1 0x1cd2
#define MT6358_LDO_VMC_CON2 0x1cd4
#define MT6358_LDO_VMC_CON3 0x1cd6
#define MT6358_LDO_VMCH_CON0 0x1cd8
#define MT6358_LDO_VMCH_CON1 0x1ce6
#define MT6358_LDO_VMCH_CON2 0x1ce8
#define MT6358_LDO_VMCH_CON3 0x1cea
#define MT6358_LDO_VIBR_CON0 0x1d08
#define MT6358_LDO_VIBR_CON1 0x1d16
#define MT6358_LDO_VIBR_CON2 0x1d18
#define MT6358_LDO_VIBR_CON3 0x1d1a
#define MT6358_LDO_VCN33_CON0_0 0x1d1c
#define MT6358_LDO_VCN33_CON0_1 0x1d2a
#define MT6358_LDO_VCN33_CON1 0x1d2c
#define MT6358_LDO_VCN33_BT_CON1 MT6358_LDO_VCN33_CON1
#define MT6358_LDO_VCN33_WIFI_CON1 MT6358_LDO_VCN33_CON1
#define MT6358_LDO_VCN33_CON2 0x1d2e
#define MT6358_LDO_VCN33_CON3 0x1d30
#define MT6358_LDO_VLDO28_CON0_0 0x1d32
#define MT6358_LDO_VLDO28_CON0_1 0x1d40
#define MT6358_LDO_VLDO28_CON1 0x1d42
#define MT6358_LDO_VLDO28_CON2 0x1d44
#define MT6358_LDO_VLDO28_CON3 0x1d46
#define MT6358_LDO_VSIM1_CON0 0x1d48
#define MT6358_LDO_VSIM1_CON1 0x1d56
#define MT6358_LDO_VSIM1_CON2 0x1d58
#define MT6358_LDO_VSIM1_CON3 0x1d5a
#define MT6358_LDO_VSIM2_CON0 0x1d5c
#define MT6358_LDO_VSIM2_CON1 0x1d6a
#define MT6358_LDO_VSIM2_CON2 0x1d6c
#define MT6358_LDO_VSIM2_CON3 0x1d6e
#define MT6358_LDO_VCN28_CON0 0x1d88
#define MT6358_LDO_VCN28_CON1 0x1d96
#define MT6358_LDO_VCN28_CON2 0x1d98
#define MT6358_LDO_VCN28_CON3 0x1d9a
#define MT6358_VRTC28_CON0 0x1d9c
#define MT6358_LDO_VBIF28_CON0 0x1d9e
#define MT6358_LDO_VBIF28_CON1 0x1dac
#define MT6358_LDO_VBIF28_CON2 0x1dae
#define MT6358_LDO_VBIF28_CON3 0x1db0
#define MT6358_VCAMA1_ANA_CON0 0x1e08
#define MT6358_VCAMA2_ANA_CON0 0x1e0c
#define MT6358_VCN33_ANA_CON0 0x1e28
#define MT6358_VSIM1_ANA_CON0 0x1e2c
#define MT6358_VSIM2_ANA_CON0 0x1e30
#define MT6358_VUSB_ANA_CON0 0x1e34
#define MT6358_VEMC_ANA_CON0 0x1e38
#define MT6358_VLDO28_ANA_CON0 0x1e3c
#define MT6358_VIO28_ANA_CON0 0x1e40
#define MT6358_VIBR_ANA_CON0 0x1e44
#define MT6358_VMCH_ANA_CON0 0x1e48
#define MT6358_VMC_ANA_CON0 0x1e4c
#define MT6358_VRF18_ANA_CON0 0x1e88
#define MT6358_VCN18_ANA_CON0 0x1e8c
#define MT6358_VCAMIO_ANA_CON0 0x1e90
#define MT6358_VIO18_ANA_CON0 0x1e94
#define MT6358_VEFUSE_ANA_CON0 0x1e98
#define MT6358_VRF12_ANA_CON0 0x1e9c
#define MT6358_VSRAM_PROC11_ANA_CON0 0x1ea0
#define MT6358_VSRAM_PROC12_ANA_CON0 0x1ea4
#define MT6358_VSRAM_OTHERS_ANA_CON0 0x1ea6
#define MT6358_VSRAM_GPU_ANA_CON0 0x1ea8
#define MT6358_VDRAM2_ANA_CON0 0x1eaa
#define MT6358_VCAMD_ANA_CON0 0x1eae
#define MT6358_VA12_ANA_CON0 0x1eb2
#define MT6358_AUD_TOP_INT_CON0 0x2228
#define MT6358_AUD_TOP_INT_STATUS0 0x2234
#endif /* __MFD_MT6358_REGISTERS_H__ */
...@@ -8,9 +8,11 @@ ...@@ -8,9 +8,11 @@
#define __MFD_MT6397_CORE_H__ #define __MFD_MT6397_CORE_H__
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/notifier.h>
enum chip_id { enum chip_id {
MT6323_CHIP_ID = 0x23, MT6323_CHIP_ID = 0x23,
MT6358_CHIP_ID = 0x58,
MT6391_CHIP_ID = 0x91, MT6391_CHIP_ID = 0x91,
MT6397_CHIP_ID = 0x97, MT6397_CHIP_ID = 0x97,
}; };
...@@ -54,6 +56,7 @@ enum mt6397_irq_numbers { ...@@ -54,6 +56,7 @@ enum mt6397_irq_numbers {
struct mt6397_chip { struct mt6397_chip {
struct device *dev; struct device *dev;
struct regmap *regmap; struct regmap *regmap;
struct notifier_block pm_nb;
int irq; int irq;
struct irq_domain *irq_domain; struct irq_domain *irq_domain;
struct mutex irqlock; struct mutex irqlock;
...@@ -63,8 +66,10 @@ struct mt6397_chip { ...@@ -63,8 +66,10 @@ struct mt6397_chip {
u16 int_con[2]; u16 int_con[2];
u16 int_status[2]; u16 int_status[2];
u16 chip_id; u16 chip_id;
void *irq_data;
}; };
int mt6358_irq_init(struct mt6397_chip *chip);
int mt6397_irq_init(struct mt6397_chip *chip); int mt6397_irq_init(struct mt6397_chip *chip);
#endif /* __MFD_MT6397_CORE_H__ */ #endif /* __MFD_MT6397_CORE_H__ */
...@@ -18,7 +18,9 @@ ...@@ -18,7 +18,9 @@
#define RTC_BBPU_CBUSY BIT(6) #define RTC_BBPU_CBUSY BIT(6)
#define RTC_BBPU_KEY (0x43 << 8) #define RTC_BBPU_KEY (0x43 << 8)
#define RTC_WRTGR 0x003c #define RTC_WRTGR_MT6358 0x003a
#define RTC_WRTGR_MT6397 0x003c
#define RTC_WRTGR_MT6323 RTC_WRTGR_MT6397
#define RTC_IRQ_STA 0x0002 #define RTC_IRQ_STA 0x0002
#define RTC_IRQ_STA_AL BIT(0) #define RTC_IRQ_STA_AL BIT(0)
...@@ -65,6 +67,10 @@ ...@@ -65,6 +67,10 @@
#define MTK_RTC_POLL_DELAY_US 10 #define MTK_RTC_POLL_DELAY_US 10
#define MTK_RTC_POLL_TIMEOUT (jiffies_to_usecs(HZ)) #define MTK_RTC_POLL_TIMEOUT (jiffies_to_usecs(HZ))
struct mtk_rtc_data {
u32 wrtgr;
};
struct mt6397_rtc { struct mt6397_rtc {
struct device *dev; struct device *dev;
struct rtc_device *rtc_dev; struct rtc_device *rtc_dev;
...@@ -74,6 +80,7 @@ struct mt6397_rtc { ...@@ -74,6 +80,7 @@ struct mt6397_rtc {
struct regmap *regmap; struct regmap *regmap;
int irq; int irq;
u32 addr_base; u32 addr_base;
const struct mtk_rtc_data *data;
}; };
#endif /* _LINUX_MFD_MT6397_RTC_H_ */ #endif /* _LINUX_MFD_MT6397_RTC_H_ */
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _GSC_HWMON_H
#define _GSC_HWMON_H
enum gsc_hwmon_mode {
mode_temperature,
mode_voltage,
mode_voltage_raw,
mode_max,
};
/**
* struct gsc_hwmon_channel - configuration parameters
* @reg: I2C register offset
* @mode: channel mode
* @name: channel name
* @mvoffset: voltage offset
* @vdiv: voltage divider array (2 resistor values in milli-ohms)
*/
struct gsc_hwmon_channel {
unsigned int reg;
unsigned int mode;
const char *name;
unsigned int mvoffset;
unsigned int vdiv[2];
};
/**
* struct gsc_hwmon_platform_data - platform data for gsc_hwmon driver
* @channels: pointer to array of gsc_hwmon_channel structures
* describing channels
* @nchannels: number of elements in @channels array
* @vreference: voltage reference (mV)
* @resolution: ADC bit resolution
* @fan_base: register base for FAN controller
*/
struct gsc_hwmon_platform_data {
const struct gsc_hwmon_channel *channels;
int nchannels;
unsigned int resolution;
unsigned int vreference;
unsigned int fan_base;
};
#endif
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