forked from luck/tmp_suning_uos_patched
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
This commit is contained in:
commit
e8a6f4acae
8
Documentation/ABI/testing/sysfs-class-power-mp2629
Normal file
8
Documentation/ABI/testing/sysfs-class-power-mp2629
Normal file
|
@ -0,0 +1,8 @@
|
|||
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].
|
196
Documentation/devicetree/bindings/mfd/gateworks-gsc.yaml
Normal file
196
Documentation/devicetree/bindings/mfd/gateworks-gsc.yaml
Normal file
|
@ -0,0 +1,196 @@
|
|||
# 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>;
|
||||
};
|
||||
};
|
||||
};
|
62
Documentation/devicetree/bindings/mfd/mps,mp2629.yaml
Normal file
62
Documentation/devicetree/bindings/mfd/mps,mp2629.yaml
Normal file
|
@ -0,0 +1,62 @@
|
|||
# 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:
|
|||
This document describes the binding for MFD device and its sub module.
|
||||
|
||||
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:
|
||||
|
||||
- rtc
|
||||
Required properties: Should be one of follows
|
||||
- compatible: "mediatek,mt6323-rtc"
|
||||
- compatible: "mediatek,mt6358-rtc"
|
||||
- compatible: "mediatek,mt6397-rtc"
|
||||
For details, see ../rtc/rtc-mt6397.txt
|
||||
- regulators
|
||||
Required properties:
|
||||
- compatible: "mediatek,mt6397-regulator"
|
||||
see ../regulator/mt6397-regulator.txt
|
||||
- compatible: "mediatek,mt6323-regulator"
|
||||
see ../regulator/mt6323-regulator.txt
|
||||
- compatible: "mediatek,mt6358-regulator"
|
||||
see ../regulator/mt6358-regulator.txt
|
||||
- compatible: "mediatek,mt6397-regulator"
|
||||
see ../regulator/mt6397-regulator.txt
|
||||
- codec
|
||||
Required properties:
|
||||
- compatible: "mediatek,mt6397-codec"
|
||||
- compatible: "mediatek,mt6397-codec" or "mediatek,mt6358-sound"
|
||||
- clk
|
||||
Required properties:
|
||||
- compatible: "mediatek,mt6397-clk"
|
||||
|
|
53
Documentation/hwmon/gsc-hwmon.rst
Normal file
53
Documentation/hwmon/gsc-hwmon.rst
Normal file
|
@ -0,0 +1,53 @@
|
|||
.. 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
|
|||
ftsteutates
|
||||
g760a
|
||||
g762
|
||||
gsc-hwmon
|
||||
gl518sm
|
||||
hih6130
|
||||
ibmaem
|
||||
|
|
16
MAINTAINERS
16
MAINTAINERS
|
@ -7028,6 +7028,17 @@ F: kernel/futex.c
|
|||
F: tools/perf/bench/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
|
||||
M: Rob Springer <rspringer@google.com>
|
||||
M: Todd Poynor <toddpoynor@google.com>
|
||||
|
@ -11382,10 +11393,15 @@ F: kernel/module.c
|
|||
MONOLITHIC POWER SYSTEM PMIC DRIVER
|
||||
M: Saravanan Sekar <sravanhome@gmail.com>
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/mfd/mps,mp2629.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/mpq7920.c
|
||||
F: drivers/regulator/mpq7920.h
|
||||
F: include/linux/mfd/mp2629.h
|
||||
|
||||
MOTION EYE VAIO PICTUREBOOK CAMERA DRIVER
|
||||
S: Orphan
|
||||
|
|
|
@ -523,6 +523,15 @@ config SENSORS_F75375S
|
|||
This driver can also be built as a module. If so, the module
|
||||
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
|
||||
tristate "Freescale MC13783/MC13892 ADC"
|
||||
depends on MFD_MC13XXX
|
||||
|
|
|
@ -74,6 +74,7 @@ obj-$(CONFIG_SENSORS_G760A) += g760a.o
|
|||
obj-$(CONFIG_SENSORS_G762) += g762.o
|
||||
obj-$(CONFIG_SENSORS_GL518SM) += gl518sm.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_HIH6130) += hih6130.o
|
||||
obj-$(CONFIG_SENSORS_ULTRA45) += ultra45_env.o
|
||||
|
|
390
drivers/hwmon/gsc-hwmon.c
Normal file
390
drivers/hwmon/gsc-hwmon.c
Normal file
|
@ -0,0 +1,390 @@
|
|||
// 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
|
|||
To compile this driver as a module, choose M here: the
|
||||
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
|
||||
tristate "Nuvoton NAU7802 ADC driver"
|
||||
depends on I2C
|
||||
|
|
|
@ -65,6 +65,7 @@ obj-$(CONFIG_MCP3911) += mcp3911.o
|
|||
obj-$(CONFIG_MEDIATEK_MT6577_AUXADC) += mt6577_auxadc.o
|
||||
obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.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_NAU7802) += nau7802.o
|
||||
obj-$(CONFIG_NPCM_ADC) += npcm_adc.o
|
||||
|
|
208
drivers/iio/adc/mp2629_adc.c
Normal file
208
drivers/iio/adc/mp2629_adc.c
Normal file
|
@ -0,0 +1,208 @@
|
|||
// 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
|
|||
Select this option to enable support for Samsung Exynos Low Power
|
||||
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
|
||||
tristate
|
||||
depends on (SPI_MASTER || I2C)
|
||||
|
@ -434,6 +449,15 @@ config MFD_MC13XXX_I2C
|
|||
help
|
||||
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
|
||||
tristate "Freescale i.MX23/i.MX28 LRADC"
|
||||
depends on ARCH_MXS || COMPILE_TEST
|
||||
|
|
|
@ -15,6 +15,7 @@ obj-$(CONFIG_MFD_BCM590XX) += bcm590xx.o
|
|||
obj-$(CONFIG_MFD_BD9571MWV) += bd9571mwv.o
|
||||
obj-$(CONFIG_MFD_CROS_EC_DEV) += cros_ec_dev.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_I2CPLD) += htc-i2cpld.o
|
||||
|
@ -170,6 +171,8 @@ obj-$(CONFIG_MFD_MAX8925) += max8925.o
|
|||
obj-$(CONFIG_MFD_MAX8997) += max8997.o max8997-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
|
||||
obj-$(CONFIG_MFD_PCF50633) += pcf50633.o
|
||||
obj-$(CONFIG_PCF50633_ADC) += pcf50633-adc.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_CHTWC) += intel_soc_pmic_chtwc.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_INTEL_SOC_PMIC_MRFLD) += intel_soc_pmic_mrfld.o
|
||||
|
||||
|
|
277
drivers/mfd/gateworks-gsc.c
Normal file
277
drivers/mfd/gateworks-gsc.c
Normal file
|
@ -0,0 +1,277 @@
|
|||
// 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, ®))
|
||||
return -EIO;
|
||||
gsc->fwver = reg;
|
||||
|
||||
regmap_read(gsc->regmap, GSC_FW_CRC, ®);
|
||||
gsc->fwcrc = reg;
|
||||
regmap_read(gsc->regmap, GSC_FW_CRC + 1, ®);
|
||||
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");
|
79
drivers/mfd/mp2629.c
Normal file
79
drivers/mfd/mp2629.c
Normal file
|
@ -0,0 +1,79 @@
|
|||
// 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");
|
235
drivers/mfd/mt6358-irq.c
Normal file
235
drivers/mfd/mt6358-irq.c
Normal file
|
@ -0,0 +1,235 @@
|
|||
// 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 @@
|
|||
#include <linux/regmap.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/mt6323/core.h>
|
||||
#include <linux/mfd/mt6358/core.h>
|
||||
#include <linux/mfd/mt6397/core.h>
|
||||
#include <linux/mfd/mt6323/registers.h>
|
||||
#include <linux/mfd/mt6358/registers.h>
|
||||
#include <linux/mfd/mt6397/registers.h>
|
||||
|
||||
#define MT6323_RTC_BASE 0x8000
|
||||
#define MT6323_RTC_SIZE 0x40
|
||||
|
||||
#define MT6358_RTC_BASE 0x0588
|
||||
#define MT6358_RTC_SIZE 0x3c
|
||||
|
||||
#define MT6397_RTC_BASE 0xe000
|
||||
#define MT6397_RTC_SIZE 0x3e
|
||||
|
||||
|
@ -30,6 +35,11 @@ static const struct resource mt6323_rtc_resources[] = {
|
|||
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[] = {
|
||||
DEFINE_RES_MEM(MT6397_RTC_BASE, MT6397_RTC_SIZE),
|
||||
DEFINE_RES_IRQ(MT6397_IRQ_RTC),
|
||||
|
@ -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[] = {
|
||||
{
|
||||
.name = "mt6397-rtc",
|
||||
|
@ -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 {
|
||||
u32 cid_addr;
|
||||
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 = {
|
||||
.cid_addr = MT6323_CID,
|
||||
.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 = {
|
||||
.cid_addr = MT6397_CID,
|
||||
.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)
|
||||
{
|
||||
int ret;
|
||||
unsigned int id;
|
||||
unsigned int id = 0;
|
||||
struct mt6397_chip *pmic;
|
||||
const struct chip_data *pmic_core;
|
||||
|
||||
|
@ -183,29 +196,13 @@ static int mt6397_probe(struct platform_device *pdev)
|
|||
if (pmic->irq <= 0)
|
||||
return pmic->irq;
|
||||
|
||||
ret = mt6397_irq_init(pmic);
|
||||
ret = pmic_core->irq_init(pmic);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
switch (pmic->chip_id) {
|
||||
case MT6323_CHIP_ID:
|
||||
ret = devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE,
|
||||
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;
|
||||
}
|
||||
|
||||
ret = devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE,
|
||||
pmic_core->cells, pmic_core->cell_size,
|
||||
NULL, 0, pmic->irq_domain);
|
||||
if (ret) {
|
||||
irq_domain_remove(pmic->irq_domain);
|
||||
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[] = {
|
|||
{
|
||||
.compatible = "mediatek,mt6323",
|
||||
.data = &mt6323_core,
|
||||
}, {
|
||||
.compatible = "mediatek,mt6358",
|
||||
.data = &mt6358_core,
|
||||
}, {
|
||||
.compatible = "mediatek,mt6397",
|
||||
.data = &mt6397_core,
|
||||
|
@ -238,7 +238,6 @@ static struct platform_driver mt6397_driver = {
|
|||
.driver = {
|
||||
.name = "mt6397",
|
||||
.of_match_table = of_match_ptr(mt6397_of_match),
|
||||
.pm = &mt6397_pm_ops,
|
||||
},
|
||||
.id_table = mt6397_id,
|
||||
};
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <linux/of_irq.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/suspend.h>
|
||||
#include <linux/mfd/mt6323/core.h>
|
||||
#include <linux/mfd/mt6323/registers.h>
|
||||
#include <linux/mfd/mt6397/core.h>
|
||||
|
@ -81,7 +82,7 @@ static struct irq_chip mt6397_irq_chip = {
|
|||
static void mt6397_irq_handle_reg(struct mt6397_chip *mt6397, int reg,
|
||||
int irqbase)
|
||||
{
|
||||
unsigned int status;
|
||||
unsigned int status = 0;
|
||||
int i, irq, ret;
|
||||
|
||||
ret = regmap_read(mt6397->regmap, reg, &status);
|
||||
|
@ -128,6 +129,36 @@ static const struct irq_domain_ops mt6397_irq_domain_ops = {
|
|||
.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 ret;
|
||||
|
@ -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[1], 0x0);
|
||||
|
||||
chip->pm_nb.notifier_call = mt6397_irq_pm_notifier;
|
||||
chip->irq_domain = irq_domain_add_linear(chip->dev->of_node,
|
||||
MT6397_IRQ_NR,
|
||||
&mt6397_irq_domain_ops,
|
||||
|
@ -177,5 +209,6 @@ int mt6397_irq_init(struct mt6397_chip *chip)
|
|||
return ret;
|
||||
}
|
||||
|
||||
register_pm_notifier(&chip->pm_nb);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ static void mt6323_do_pwroff(void)
|
|||
int ret;
|
||||
|
||||
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,
|
||||
pwrc->base + RTC_BBPU, val,
|
||||
|
|
|
@ -541,6 +541,16 @@ config CHARGER_MAX8998
|
|||
Say Y to enable support for the battery charger control sysfs and
|
||||
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
|
||||
tristate "Qualcomm Switch-Mode Battery Charger and Boost"
|
||||
depends on MFD_SPMI_PMIC || COMPILE_TEST
|
||||
|
|
|
@ -75,6 +75,7 @@ obj-$(CONFIG_CHARGER_MAX77650) += max77650-charger.o
|
|||
obj-$(CONFIG_CHARGER_MAX77693) += max77693_charger.o
|
||||
obj-$(CONFIG_CHARGER_MAX8997) += max8997_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_BQ2415X) += bq2415x_charger.o
|
||||
obj-$(CONFIG_CHARGER_BQ24190) += bq24190_charger.o
|
||||
|
|
669
drivers/power/supply/mp2629_charger.c
Normal file
669
drivers/power/supply/mp2629_charger.c
Normal file
|
@ -0,0 +1,669 @@
|
|||
// 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 @@
|
|||
#include <linux/mfd/mt6397/core.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/rtc.h>
|
||||
|
@ -20,7 +21,7 @@ static int mtk_rtc_write_trigger(struct mt6397_rtc *rtc)
|
|||
int ret;
|
||||
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)
|
||||
return ret;
|
||||
|
||||
|
@ -269,6 +270,8 @@ static int mtk_rtc_probe(struct platform_device *pdev)
|
|||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
rtc->addr_base = res->start;
|
||||
|
||||
rtc->data = of_device_get_match_data(&pdev->dev);
|
||||
|
||||
rtc->irq = platform_get_irq(pdev, 0);
|
||||
if (rtc->irq < 0)
|
||||
return rtc->irq;
|
||||
|
@ -325,9 +328,18 @@ static int mt6397_rtc_resume(struct device *dev)
|
|||
static SIMPLE_DEV_PM_OPS(mt6397_pm_ops, mt6397_rtc_suspend,
|
||||
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[] = {
|
||||
{ .compatible = "mediatek,mt6323-rtc", },
|
||||
{ .compatible = "mediatek,mt6397-rtc", },
|
||||
{ .compatible = "mediatek,mt6323-rtc", .data = &mt6397_rtc_data },
|
||||
{ .compatible = "mediatek,mt6358-rtc", .data = &mt6358_rtc_data },
|
||||
{ .compatible = "mediatek,mt6397-rtc", .data = &mt6397_rtc_data },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, mt6397_rtc_of_match);
|
||||
|
|
76
include/linux/mfd/gsc.h
Normal file
76
include/linux/mfd/gsc.h
Normal file
|
@ -0,0 +1,76 @@
|
|||
/* 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_ */
|
26
include/linux/mfd/mp2629.h
Normal file
26
include/linux/mfd/mp2629.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
/* 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
|
158
include/linux/mfd/mt6358/core.h
Normal file
158
include/linux/mfd/mt6358/core.h
Normal file
|
@ -0,0 +1,158 @@
|
|||
/* 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__ */
|
282
include/linux/mfd/mt6358/registers.h
Normal file
282
include/linux/mfd/mt6358/registers.h
Normal file
|
@ -0,0 +1,282 @@
|
|||
/* 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 @@
|
|||
#define __MFD_MT6397_CORE_H__
|
||||
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/notifier.h>
|
||||
|
||||
enum chip_id {
|
||||
MT6323_CHIP_ID = 0x23,
|
||||
MT6358_CHIP_ID = 0x58,
|
||||
MT6391_CHIP_ID = 0x91,
|
||||
MT6397_CHIP_ID = 0x97,
|
||||
};
|
||||
|
@ -54,6 +56,7 @@ enum mt6397_irq_numbers {
|
|||
struct mt6397_chip {
|
||||
struct device *dev;
|
||||
struct regmap *regmap;
|
||||
struct notifier_block pm_nb;
|
||||
int irq;
|
||||
struct irq_domain *irq_domain;
|
||||
struct mutex irqlock;
|
||||
|
@ -63,8 +66,10 @@ struct mt6397_chip {
|
|||
u16 int_con[2];
|
||||
u16 int_status[2];
|
||||
u16 chip_id;
|
||||
void *irq_data;
|
||||
};
|
||||
|
||||
int mt6358_irq_init(struct mt6397_chip *chip);
|
||||
int mt6397_irq_init(struct mt6397_chip *chip);
|
||||
|
||||
#endif /* __MFD_MT6397_CORE_H__ */
|
||||
|
|
|
@ -18,7 +18,9 @@
|
|||
#define RTC_BBPU_CBUSY BIT(6)
|
||||
#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_AL BIT(0)
|
||||
|
@ -65,6 +67,10 @@
|
|||
#define MTK_RTC_POLL_DELAY_US 10
|
||||
#define MTK_RTC_POLL_TIMEOUT (jiffies_to_usecs(HZ))
|
||||
|
||||
struct mtk_rtc_data {
|
||||
u32 wrtgr;
|
||||
};
|
||||
|
||||
struct mt6397_rtc {
|
||||
struct device *dev;
|
||||
struct rtc_device *rtc_dev;
|
||||
|
@ -74,6 +80,7 @@ struct mt6397_rtc {
|
|||
struct regmap *regmap;
|
||||
int irq;
|
||||
u32 addr_base;
|
||||
const struct mtk_rtc_data *data;
|
||||
};
|
||||
|
||||
#endif /* _LINUX_MFD_MT6397_RTC_H_ */
|
||||
|
|
44
include/linux/platform_data/gsc_hwmon.h
Normal file
44
include/linux/platform_data/gsc_hwmon.h
Normal file
|
@ -0,0 +1,44 @@
|
|||
/* 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
|
Loading…
Reference in New Issue
Block a user