- New Drivers
- Add support for IQS620A/621/622/624/625 Azoteq IQS62X Sensors - New Device Support - Add support for ADC, IRQ, Regulator, RTC and WDT to Ricoh RN5T618 PMIC - Add support for Comet Lake to Intel LPSS - New Functionality - Add support for Charger Detection to Spreadtrum SC27xx PMICs - Add support for Interrupt Polarity to Dialog Semi DA9062/61 PMIC - Add ACPI enumeration support to Diolan DLN2 USB Adaptor - Fix-ups - Device Tree; iqs62x, rn5t618, cros_ec_dev, stm32-lptimer, rohm,bd71837, rohm,bd71847 - I2C registration; rn5t618 - Kconfig; MFD_CPCAP, AB8500_CORE, MFD_WM8994, MFD_WM97xx, MFD_STPMIC1 - Use flexible-array members; omap-usb-tll, qcom-pm8xxx - Remove unnecessary casts; omap-usb-host, omap-usb-tll - Power (suspend/resume/poweroff) enhancements; rk808 - Improve error/sanity checking; dln2 - Use snprintf(); aat2870-core - Bug Fixes - Fix PCI IDs; intel-lpss-pci -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEdrbJNaO+IJqU8IdIUa+KL4f8d2EFAl6MSwsACgkQUa+KL4f8 d2GklhAAk1e0tYu1w4yS0IE40mReDk5ycOE1O8Q75qWw5Af2dK48qvSHGDwaU4ES WNYZ3Mr/OUrvd+/XU8EXI6NXAi9W75ye2J2KmmDDL6yXnDuHbzBZF8ifEtXQKSOp rElzCJVnXehpjSfwa4cp5f1Msox/rFg1Kpmaas48j8U2JYCmn51GsQCCG6qMIx2i 0ZvXNZuz+eTY3V7l6pRLfTYqwR8E5Y11ryWJaeliyDcVpUlZaykiXuxD7pbqLjJo 8v9ISm67rzf6X5zmi6YhdvpIAzpomdRaaxHfVDkeCKqDgpuWGiq0xXA86vDKwjah qVx6rK/wg4YM5uSEomxIgVj9uvvLSytDqvRlPe7vFKgkR0Xhl5SdkiwadI4P9zkr zrRGNRAUHsZ4ZrlObD0QJWOQYnIg5oCmRouRKcHtQVZYP3rSdRz/1oC6FN8LVqUw 3NfLB/S6uBCJ3uahckrgnjQughnvmsAzlflcNV2t+P8di8Cwyh2A5N9qkT/oI67o Xf7NODSdu0JzzTgsM+EJ2JphSLMYaekWs06qAXyibPrrS2SoThE79igCmNOkyyR7 obJfN2SM5k4LkhMGlYbPfbRT2Hoa+9OJozBe3WgiW3kwTdFVB9aen2U230tHplbB g/NuVS+PrReR5lfzT+O8dodH7lj5/GhmGsapdguFVhXYIE+2CMg= =hJ2o -----END PGP SIGNATURE----- Merge tag 'mfd-next-5.7' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd Pull mfd updates from Lee Jones: "New Drivers: - Add support for IQS620A/621/622/624/625 Azoteq IQS62X Sensors New Device Support: - Add support for ADC, IRQ, Regulator, RTC and WDT to Ricoh RN5T618 PMIC - Add support for Comet Lake to Intel LPSS New Functionality: - Add support for Charger Detection to Spreadtrum SC27xx PMICs - Add support for Interrupt Polarity to Dialog Semi DA9062/61 PMIC - Add ACPI enumeration support to Diolan DLN2 USB Adaptor Fix-ups: - Device Tree; iqs62x, rn5t618, cros_ec_dev, stm32-lptimer, rohm,bd71837, rohm,bd71847 - I2C registration; rn5t618 - Kconfig; MFD_CPCAP, AB8500_CORE, MFD_WM8994, MFD_WM97xx, MFD_STPMIC1 - Use flexible-array members; omap-usb-tll, qcom-pm8xxx - Remove unnecessary casts; omap-usb-host, omap-usb-tll - Power (suspend/resume/poweroff) enhancements; rk808 - Improve error/sanity checking; dln2 - Use snprintf(); aat2870-core Bug Fixes: - Fix PCI IDs in intel-lpss-pci" * tag 'mfd-next-5.7' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd: (33 commits) mfd: intel-lpss: Fix Intel Elkhart Lake LPSS I2C input clock mfd: aat2870: Use scnprintf() for avoiding potential buffer overflow mfd: dln2: Allow to be enumerated via ACPI mfd: da9062: Add support for interrupt polarity defined in device tree dt-bindings: bd718x7: Yamlify and add BD71850 mfd: dln2: Fix sanity checking for endpoints mfd: intel-lpss: Add Intel Comet Lake PCH-V PCI IDs mfd: sc27xx: Add USB charger type detection support dt-bindings: mfd: Document STM32 low power timer bindings mfd: rk808: Convert RK805 to shutdown/suspend hooks mfd: rk808: Reduce shutdown duplication mfd: rk808: Stop using syscore ops mfd: rk808: Ensure suspend/resume hooks always work mfd: rk808: Always use poweroff when requested mfd: omap: Remove useless cast for driver.name mfd: Kconfig: Fix some misspelling of the word functionality mfd: pm8xxx: Replace zero-length array with flexible-array member mfd: omap-usb-tll: Replace zero-length array with flexible-array member mfd: cpcap: Fix compile if MFD_CORE is not selected mfd: cros_ec: Check DT node for usbpd-notify add ...
This commit is contained in:
commit
8645f09bad
|
@ -0,0 +1,132 @@
|
||||||
|
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: http://devicetree.org/schemas/input/iqs62x-keys.yaml#
|
||||||
|
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||||
|
|
||||||
|
title: Azoteq IQS620A/621/622/624/625 Keys and Switches
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Jeff LaBundy <jeff@labundy.com>
|
||||||
|
|
||||||
|
description: |
|
||||||
|
The Azoteq IQS620A, IQS621, IQS622, IQS624 and IQS625 multi-function sensors
|
||||||
|
feature a variety of self-capacitive, mutual-inductive and Hall-effect sens-
|
||||||
|
ing capabilities that can facilitate a variety of contactless key and switch
|
||||||
|
applications.
|
||||||
|
|
||||||
|
These functions are collectively represented by a "keys" child node from the
|
||||||
|
parent MFD driver. See Documentation/devicetree/bindings/mfd/iqs62x.yaml for
|
||||||
|
further details and examples. Sensor hardware configuration (self-capacitive
|
||||||
|
vs. mutual-inductive, etc.) is selected based on the device's firmware.
|
||||||
|
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
enum:
|
||||||
|
- azoteq,iqs620a-keys
|
||||||
|
- azoteq,iqs621-keys
|
||||||
|
- azoteq,iqs622-keys
|
||||||
|
- azoteq,iqs624-keys
|
||||||
|
- azoteq,iqs625-keys
|
||||||
|
|
||||||
|
linux,keycodes:
|
||||||
|
allOf:
|
||||||
|
- $ref: /schemas/types.yaml#/definitions/uint32-array
|
||||||
|
- minItems: 1
|
||||||
|
maxItems: 16
|
||||||
|
description: |
|
||||||
|
Specifies the numeric keycodes associated with each available touch or
|
||||||
|
proximity event according to the following table. An 'x' indicates the
|
||||||
|
event is supported for a given device. Specify 0 for unused events.
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------
|
||||||
|
| # | Event | IQS620A | IQS621 | IQS622 | IQS624 | IQS625 |
|
||||||
|
-------------------------------------------------------------------------
|
||||||
|
| 0 | CH0 Touch | x | x | x | x | x |
|
||||||
|
| | Antenna 1 Touch* | x | | | | |
|
||||||
|
-------------------------------------------------------------------------
|
||||||
|
| 1 | CH0 Proximity | x | x | x | x | x |
|
||||||
|
| | Antenna 1 Prox.* | x | | | | |
|
||||||
|
-------------------------------------------------------------------------
|
||||||
|
| 2 | CH1 Touch | x | x | x | x | x |
|
||||||
|
| | Ant. 1 Deep Touch* | x | | | | |
|
||||||
|
-------------------------------------------------------------------------
|
||||||
|
| 3 | CH1 Proximity | x | x | x | x | x |
|
||||||
|
-------------------------------------------------------------------------
|
||||||
|
| 4 | CH2 Touch | x | | | | |
|
||||||
|
-------------------------------------------------------------------------
|
||||||
|
| 5 | CH2 Proximity | x | | | | |
|
||||||
|
| | Antenna 2 Prox.* | x | | | | |
|
||||||
|
-------------------------------------------------------------------------
|
||||||
|
| 6 | Metal (+) Touch** | x | x | | | |
|
||||||
|
| | Ant. 2 Deep Touch* | x | | | | |
|
||||||
|
-------------------------------------------------------------------------
|
||||||
|
| 7 | Metal (+) Prox.** | x | x | | | |
|
||||||
|
| | Antenna 2 Touch* | x | | | | |
|
||||||
|
-------------------------------------------------------------------------
|
||||||
|
| 8 | Metal (-) Touch** | x | x | | | |
|
||||||
|
-------------------------------------------------------------------------
|
||||||
|
| 9 | Metal (-) Prox.** | x | x | | | |
|
||||||
|
-------------------------------------------------------------------------
|
||||||
|
| 10 | SAR Active*** | x | | x | | |
|
||||||
|
-------------------------------------------------------------------------
|
||||||
|
| 11 | SAR Quick Rel.*** | x | | x | | |
|
||||||
|
-------------------------------------------------------------------------
|
||||||
|
| 12 | SAR Movement*** | x | | x | | |
|
||||||
|
-------------------------------------------------------------------------
|
||||||
|
| 13 | SAR Filter Halt*** | x | | x | | |
|
||||||
|
-------------------------------------------------------------------------
|
||||||
|
| 14 | Wheel Up | | | | x | |
|
||||||
|
-------------------------------------------------------------------------
|
||||||
|
| 15 | Wheel Down | | | | x | |
|
||||||
|
-------------------------------------------------------------------------
|
||||||
|
* Two-channel SAR. Replaces CH0-2 plus metal touch and proximity events
|
||||||
|
if enabled via firmware.
|
||||||
|
** "+" and "-" refer to the polarity of a channel's delta (LTA - counts),
|
||||||
|
where "LTA" is defined as the channel's long-term average.
|
||||||
|
*** One-channel SAR. Replaces CH0-2 touch and proximity events if enabled
|
||||||
|
via firmware.
|
||||||
|
|
||||||
|
patternProperties:
|
||||||
|
"^hall-switch-(north|south)$":
|
||||||
|
type: object
|
||||||
|
description:
|
||||||
|
Represents north/south-field Hall-effect sensor touch or proximity
|
||||||
|
events. Note that north/south-field orientation is reversed on the
|
||||||
|
IQS620AXzCSR device due to its flip-chip package.
|
||||||
|
|
||||||
|
properties:
|
||||||
|
linux,code:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
description: Numeric switch code associated with the event.
|
||||||
|
|
||||||
|
azoteq,use-prox:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/flag
|
||||||
|
description:
|
||||||
|
If present, specifies that Hall-effect sensor reporting should
|
||||||
|
use the device's wide-range proximity threshold instead of its
|
||||||
|
close-range touch threshold (default).
|
||||||
|
|
||||||
|
required:
|
||||||
|
- linux,code
|
||||||
|
|
||||||
|
additionalProperties: false
|
||||||
|
|
||||||
|
if:
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
contains:
|
||||||
|
enum:
|
||||||
|
- azoteq,iqs624-keys
|
||||||
|
- azoteq,iqs625-keys
|
||||||
|
then:
|
||||||
|
patternProperties:
|
||||||
|
"^hall-switch-(north|south)$": false
|
||||||
|
|
||||||
|
required:
|
||||||
|
- compatible
|
||||||
|
- linux,keycodes
|
||||||
|
|
||||||
|
additionalProperties: false
|
||||||
|
|
||||||
|
...
|
|
@ -0,0 +1,179 @@
|
||||||
|
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: http://devicetree.org/schemas/mfd/iqs62x.yaml#
|
||||||
|
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||||
|
|
||||||
|
title: Azoteq IQS620A/621/622/624/625 Multi-Function Sensors
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Jeff LaBundy <jeff@labundy.com>
|
||||||
|
|
||||||
|
description: |
|
||||||
|
The Azoteq IQS620A, IQS621, IQS622, IQS624 and IQS625 multi-function sensors
|
||||||
|
integrate multiple sensing technologies in a single package.
|
||||||
|
|
||||||
|
Link to datasheets: https://www.azoteq.com/
|
||||||
|
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
enum:
|
||||||
|
- azoteq,iqs620a
|
||||||
|
- azoteq,iqs621
|
||||||
|
- azoteq,iqs622
|
||||||
|
- azoteq,iqs624
|
||||||
|
- azoteq,iqs625
|
||||||
|
|
||||||
|
reg:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
interrupts:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
firmware-name:
|
||||||
|
$ref: /schemas/types.yaml#/definitions/string
|
||||||
|
description:
|
||||||
|
Specifies the name of the calibration and configuration file selected by
|
||||||
|
the driver. If this property is omitted, the name is chosen based on the
|
||||||
|
device name with ".bin" as the extension (e.g. iqs620a.bin for IQS620A).
|
||||||
|
|
||||||
|
keys:
|
||||||
|
$ref: ../input/iqs62x-keys.yaml
|
||||||
|
|
||||||
|
pwm:
|
||||||
|
$ref: ../pwm/iqs620a-pwm.yaml
|
||||||
|
|
||||||
|
required:
|
||||||
|
- compatible
|
||||||
|
- reg
|
||||||
|
- interrupts
|
||||||
|
|
||||||
|
additionalProperties: false
|
||||||
|
|
||||||
|
examples:
|
||||||
|
- |
|
||||||
|
/*
|
||||||
|
* Dual capacitive buttons with proximity-activated function, unipolar lid
|
||||||
|
* switch and panel-mounted LED.
|
||||||
|
*/
|
||||||
|
#include <dt-bindings/input/input.h>
|
||||||
|
#include <dt-bindings/interrupt-controller/irq.h>
|
||||||
|
|
||||||
|
i2c {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
|
||||||
|
iqs620a@44 {
|
||||||
|
compatible = "azoteq,iqs620a";
|
||||||
|
reg = <0x44>;
|
||||||
|
interrupt-parent = <&gpio>;
|
||||||
|
interrupts = <17 IRQ_TYPE_LEVEL_LOW>;
|
||||||
|
|
||||||
|
keys {
|
||||||
|
compatible = "azoteq,iqs620a-keys";
|
||||||
|
|
||||||
|
linux,keycodes = <KEY_SELECT>,
|
||||||
|
<KEY_MENU>,
|
||||||
|
<KEY_OK>,
|
||||||
|
<KEY_MENU>;
|
||||||
|
|
||||||
|
hall-switch-south {
|
||||||
|
linux,code = <SW_LID>;
|
||||||
|
azoteq,use-prox;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
iqs620a_pwm: pwm {
|
||||||
|
compatible = "azoteq,iqs620a-pwm";
|
||||||
|
#pwm-cells = <2>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
pwmleds {
|
||||||
|
compatible = "pwm-leds";
|
||||||
|
|
||||||
|
panel {
|
||||||
|
pwms = <&iqs620a_pwm 0 1000000>;
|
||||||
|
max-brightness = <255>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
- |
|
||||||
|
/* Single inductive button with bipolar dock/tablet-mode switch. */
|
||||||
|
#include <dt-bindings/input/input.h>
|
||||||
|
#include <dt-bindings/interrupt-controller/irq.h>
|
||||||
|
|
||||||
|
i2c {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
|
||||||
|
iqs620a@44 {
|
||||||
|
compatible = "azoteq,iqs620a";
|
||||||
|
reg = <0x44>;
|
||||||
|
interrupt-parent = <&gpio>;
|
||||||
|
interrupts = <17 IRQ_TYPE_LEVEL_LOW>;
|
||||||
|
|
||||||
|
firmware-name = "iqs620a_coil.bin";
|
||||||
|
|
||||||
|
keys {
|
||||||
|
compatible = "azoteq,iqs620a-keys";
|
||||||
|
|
||||||
|
linux,keycodes = <0>,
|
||||||
|
<0>,
|
||||||
|
<0>,
|
||||||
|
<0>,
|
||||||
|
<0>,
|
||||||
|
<0>,
|
||||||
|
<KEY_MUTE>;
|
||||||
|
|
||||||
|
hall-switch-north {
|
||||||
|
linux,code = <SW_DOCK>;
|
||||||
|
};
|
||||||
|
|
||||||
|
hall-switch-south {
|
||||||
|
linux,code = <SW_TABLET_MODE>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
- |
|
||||||
|
/* Dual capacitive buttons with volume knob. */
|
||||||
|
#include <dt-bindings/input/input.h>
|
||||||
|
#include <dt-bindings/interrupt-controller/irq.h>
|
||||||
|
|
||||||
|
i2c {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
|
||||||
|
iqs624@44 {
|
||||||
|
compatible = "azoteq,iqs624";
|
||||||
|
reg = <0x44>;
|
||||||
|
interrupt-parent = <&gpio>;
|
||||||
|
interrupts = <17 IRQ_TYPE_LEVEL_LOW>;
|
||||||
|
|
||||||
|
keys {
|
||||||
|
compatible = "azoteq,iqs624-keys";
|
||||||
|
|
||||||
|
linux,keycodes = <BTN_0>,
|
||||||
|
<0>,
|
||||||
|
<BTN_1>,
|
||||||
|
<0>,
|
||||||
|
<0>,
|
||||||
|
<0>,
|
||||||
|
<0>,
|
||||||
|
<0>,
|
||||||
|
<0>,
|
||||||
|
<0>,
|
||||||
|
<0>,
|
||||||
|
<0>,
|
||||||
|
<0>,
|
||||||
|
<0>,
|
||||||
|
<KEY_VOLUMEUP>,
|
||||||
|
<KEY_VOLUMEDOWN>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
...
|
|
@ -15,6 +15,8 @@ Required properties:
|
||||||
- reg: the I2C slave address of the device
|
- reg: the I2C slave address of the device
|
||||||
|
|
||||||
Optional properties:
|
Optional properties:
|
||||||
|
- interrupts: interrupt mapping for IRQ
|
||||||
|
See Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
|
||||||
- system-power-controller:
|
- system-power-controller:
|
||||||
See Documentation/devicetree/bindings/power/power-controller.txt
|
See Documentation/devicetree/bindings/power/power-controller.txt
|
||||||
|
|
||||||
|
@ -32,6 +34,8 @@ Example:
|
||||||
pmic@32 {
|
pmic@32 {
|
||||||
compatible = "ricoh,rn5t618";
|
compatible = "ricoh,rn5t618";
|
||||||
reg = <0x32>;
|
reg = <0x32>;
|
||||||
|
interrupt-parent = <&gpio5>;
|
||||||
|
interrupts = <11 IRQ_TYPE_EDGE_FALLING>;
|
||||||
system-power-controller;
|
system-power-controller;
|
||||||
|
|
||||||
regulators {
|
regulators {
|
||||||
|
|
|
@ -1,90 +0,0 @@
|
||||||
* ROHM BD71837 and BD71847 Power Management Integrated Circuit bindings
|
|
||||||
|
|
||||||
BD71837MWV and BD71847MWV are programmable Power Management ICs for powering
|
|
||||||
single-core, dual-core, and quad-core SoCs such as NXP-i.MX 8M. They are
|
|
||||||
optimized for low BOM cost and compact solution footprint. BD71837MWV
|
|
||||||
integrates 8 Buck regulators and 7 LDOs. BD71847MWV contains 6 Buck regulators
|
|
||||||
and 6 LDOs.
|
|
||||||
|
|
||||||
Datasheet for BD71837 is available at:
|
|
||||||
https://www.rohm.com/datasheet/BD71837MWV/bd71837mwv-e
|
|
||||||
Datasheet for BD71847 is available at:
|
|
||||||
https://www.rohm.com/datasheet/BD71847AMWV/bd71847amwv-e
|
|
||||||
|
|
||||||
Required properties:
|
|
||||||
- compatible : Should be "rohm,bd71837" for bd71837
|
|
||||||
"rohm,bd71847" for bd71847.
|
|
||||||
- reg : I2C slave address.
|
|
||||||
- interrupt-parent : Phandle to the parent interrupt controller.
|
|
||||||
- interrupts : The interrupt line the device is connected to.
|
|
||||||
- clocks : The parent clock connected to PMIC. If this is missing
|
|
||||||
32768 KHz clock is assumed.
|
|
||||||
- #clock-cells : Should be 0.
|
|
||||||
- regulators: : List of child nodes that specify the regulators.
|
|
||||||
Please see ../regulator/rohm,bd71837-regulator.txt
|
|
||||||
|
|
||||||
Optional properties:
|
|
||||||
- clock-output-names : Should contain name for output clock.
|
|
||||||
- rohm,reset-snvs-powered : Transfer BD718x7 to SNVS state at reset.
|
|
||||||
|
|
||||||
The BD718x7 supports two different HW states as reset target states. States
|
|
||||||
are called as SNVS and READY. At READY state all the PMIC power outputs go
|
|
||||||
down and OTP is reload. At the SNVS state all other logic and external
|
|
||||||
devices apart from the SNVS power domain are shut off. Please refer to NXP
|
|
||||||
i.MX8 documentation for further information regarding SNVS state. When a
|
|
||||||
reset is done via SNVS state the PMIC OTP data is not reload. This causes
|
|
||||||
power outputs that have been under SW control to stay down when reset has
|
|
||||||
switched power state to SNVS. If reset is done via READY state the power
|
|
||||||
outputs will be returned to HW control by OTP loading. Thus the reset
|
|
||||||
target state is set to READY by default. If SNVS state is used the boot
|
|
||||||
crucial regulators must have the regulator-always-on and regulator-boot-on
|
|
||||||
properties set in regulator node.
|
|
||||||
|
|
||||||
- rohm,short-press-ms : Short press duration in milliseconds
|
|
||||||
- rohm,long-press-ms : Long press duration in milliseconds
|
|
||||||
|
|
||||||
Configure the "short press" and "long press" timers for the power button.
|
|
||||||
Values are rounded to what hardware supports (500ms multiple for short and
|
|
||||||
1000ms multiple for long). If these properties are not present the existing
|
|
||||||
configuration (from bootloader or OTP) is not touched.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
/* external oscillator node */
|
|
||||||
osc: oscillator {
|
|
||||||
compatible = "fixed-clock";
|
|
||||||
#clock-cells = <1>;
|
|
||||||
clock-frequency = <32768>;
|
|
||||||
clock-output-names = "osc";
|
|
||||||
};
|
|
||||||
|
|
||||||
pmic: pmic@4b {
|
|
||||||
compatible = "rohm,bd71837";
|
|
||||||
reg = <0x4b>;
|
|
||||||
interrupt-parent = <&gpio1>;
|
|
||||||
interrupts = <29 GPIO_ACTIVE_LOW>;
|
|
||||||
interrupt-names = "irq";
|
|
||||||
#clock-cells = <0>;
|
|
||||||
clocks = <&osc 0>;
|
|
||||||
clock-output-names = "bd71837-32k-out";
|
|
||||||
rohm,reset-snvs-powered;
|
|
||||||
|
|
||||||
regulators {
|
|
||||||
buck1: BUCK1 {
|
|
||||||
regulator-name = "buck1";
|
|
||||||
regulator-min-microvolt = <700000>;
|
|
||||||
regulator-max-microvolt = <1300000>;
|
|
||||||
regulator-boot-on;
|
|
||||||
regulator-always-on;
|
|
||||||
regulator-ramp-delay = <1250>;
|
|
||||||
};
|
|
||||||
// [...]
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Clock consumer node */
|
|
||||||
rtc@0 {
|
|
||||||
compatible = "company,my-rtc";
|
|
||||||
clock-names = "my-clock";
|
|
||||||
clocks = <&pmic>;
|
|
||||||
};
|
|
|
@ -0,0 +1,236 @@
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: http://devicetree.org/schemas/mfd/rohm,bd71837-pmic.yaml#
|
||||||
|
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||||
|
|
||||||
|
title: ROHM BD71837 Power Management Integrated Circuit bindings
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
|
||||||
|
|
||||||
|
description: |
|
||||||
|
BD71837MWV is programmable Power Management ICs for powering single-core,
|
||||||
|
dual-core, and quad-core SoCs such as NXP-i.MX 8M. It is optimized for low
|
||||||
|
BOM cost and compact solution footprint. BD71837MWV integrates 8 Buck
|
||||||
|
regulators and 7 LDOs.
|
||||||
|
Datasheet for BD71837 is available at
|
||||||
|
https://www.rohm.com/products/power-management/power-management-ic-for-system/industrial-consumer-applications/nxp-imx/bd71837amwv-product
|
||||||
|
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
const: rohm,bd71837
|
||||||
|
|
||||||
|
reg:
|
||||||
|
description:
|
||||||
|
I2C slave address.
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
interrupts:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
clocks:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
"#clock-cells":
|
||||||
|
const: 0
|
||||||
|
|
||||||
|
# The BD718x7 supports two different HW states as reset target states. States
|
||||||
|
# are called as SNVS and READY. At READY state all the PMIC power outputs go
|
||||||
|
# down and OTP is reload. At the SNVS state all other logic and external
|
||||||
|
# devices apart from the SNVS power domain are shut off. Please refer to NXP
|
||||||
|
# i.MX8 documentation for further information regarding SNVS state. When a
|
||||||
|
# reset is done via SNVS state the PMIC OTP data is not reload. This causes
|
||||||
|
# power outputs that have been under SW control to stay down when reset has
|
||||||
|
# switched power state to SNVS. If reset is done via READY state the power
|
||||||
|
# outputs will be returned to HW control by OTP loading. Thus the reset
|
||||||
|
# target state is set to READY by default. If SNVS state is used the boot
|
||||||
|
# crucial regulators must have the regulator-always-on and regulator-boot-on
|
||||||
|
# properties set in regulator node.
|
||||||
|
|
||||||
|
rohm,reset-snvs-powered:
|
||||||
|
description: |
|
||||||
|
Transfer PMIC to SNVS state at reset
|
||||||
|
type: boolean
|
||||||
|
|
||||||
|
# Configure the "short press" and "long press" timers for the power button.
|
||||||
|
# Values are rounded to what hardware supports
|
||||||
|
# Short-press:
|
||||||
|
# Shortest being 10ms, next 500ms and then multiple of 500ms up to 7,5s
|
||||||
|
# Long-press:
|
||||||
|
# Shortest being 10ms, next 1000ms and then multiple of 1000ms up to 15s
|
||||||
|
# If these properties are not present the existing configuration (from
|
||||||
|
# bootloader or OTP) is not touched.
|
||||||
|
|
||||||
|
rohm,short-press-ms:
|
||||||
|
description:
|
||||||
|
Short press duration in milliseconds
|
||||||
|
enum:
|
||||||
|
- 10
|
||||||
|
- 500
|
||||||
|
- 1000
|
||||||
|
- 1500
|
||||||
|
- 2000
|
||||||
|
- 2500
|
||||||
|
- 3000
|
||||||
|
- 3500
|
||||||
|
- 4000
|
||||||
|
- 4500
|
||||||
|
- 5000
|
||||||
|
- 5500
|
||||||
|
- 6000
|
||||||
|
- 6500
|
||||||
|
- 7000
|
||||||
|
|
||||||
|
rohm,long-press-ms:
|
||||||
|
description:
|
||||||
|
Long press duration in milliseconds
|
||||||
|
enum:
|
||||||
|
- 10
|
||||||
|
- 1000
|
||||||
|
- 2000
|
||||||
|
- 3000
|
||||||
|
- 4000
|
||||||
|
- 5000
|
||||||
|
- 6000
|
||||||
|
- 7000
|
||||||
|
- 8000
|
||||||
|
- 9000
|
||||||
|
- 10000
|
||||||
|
- 11000
|
||||||
|
- 12000
|
||||||
|
- 13000
|
||||||
|
- 14000
|
||||||
|
|
||||||
|
regulators:
|
||||||
|
$ref: ../regulator/rohm,bd71837-regulator.yaml
|
||||||
|
description:
|
||||||
|
List of child nodes that specify the regulators.
|
||||||
|
|
||||||
|
required:
|
||||||
|
- compatible
|
||||||
|
- reg
|
||||||
|
- interrupts
|
||||||
|
- clocks
|
||||||
|
- "#clock-cells"
|
||||||
|
- regulators
|
||||||
|
|
||||||
|
additionalProperties: false
|
||||||
|
|
||||||
|
examples:
|
||||||
|
- |
|
||||||
|
#include <dt-bindings/interrupt-controller/irq.h>
|
||||||
|
#include <dt-bindings/leds/common.h>
|
||||||
|
|
||||||
|
i2c {
|
||||||
|
pmic: pmic@4b {
|
||||||
|
compatible = "rohm,bd71837";
|
||||||
|
reg = <0x4b>;
|
||||||
|
interrupt-parent = <&gpio1>;
|
||||||
|
interrupts = <29 IRQ_TYPE_LEVEL_LOW>;
|
||||||
|
#clock-cells = <0>;
|
||||||
|
clocks = <&osc 0>;
|
||||||
|
rohm,reset-snvs-powered;
|
||||||
|
rohm,short-press-ms = <10>;
|
||||||
|
rohm,long-press-ms = <2000>;
|
||||||
|
|
||||||
|
regulators {
|
||||||
|
buck1: BUCK1 {
|
||||||
|
regulator-name = "buck1";
|
||||||
|
regulator-min-microvolt = <700000>;
|
||||||
|
regulator-max-microvolt = <1300000>;
|
||||||
|
regulator-boot-on;
|
||||||
|
regulator-always-on;
|
||||||
|
regulator-ramp-delay = <1250>;
|
||||||
|
rohm,dvs-run-voltage = <900000>;
|
||||||
|
rohm,dvs-idle-voltage = <850000>;
|
||||||
|
rohm,dvs-suspend-voltage = <800000>;
|
||||||
|
};
|
||||||
|
buck2: BUCK2 {
|
||||||
|
regulator-name = "buck2";
|
||||||
|
regulator-min-microvolt = <700000>;
|
||||||
|
regulator-max-microvolt = <1300000>;
|
||||||
|
regulator-boot-on;
|
||||||
|
regulator-always-on;
|
||||||
|
regulator-ramp-delay = <1250>;
|
||||||
|
rohm,dvs-run-voltage = <1000000>;
|
||||||
|
rohm,dvs-idle-voltage = <900000>;
|
||||||
|
};
|
||||||
|
buck3: BUCK3 {
|
||||||
|
regulator-name = "buck3";
|
||||||
|
regulator-min-microvolt = <700000>;
|
||||||
|
regulator-max-microvolt = <1300000>;
|
||||||
|
regulator-boot-on;
|
||||||
|
rohm,dvs-run-voltage = <1000000>;
|
||||||
|
};
|
||||||
|
buck4: BUCK4 {
|
||||||
|
regulator-name = "buck4";
|
||||||
|
regulator-min-microvolt = <700000>;
|
||||||
|
regulator-max-microvolt = <1300000>;
|
||||||
|
regulator-boot-on;
|
||||||
|
rohm,dvs-run-voltage = <1000000>;
|
||||||
|
};
|
||||||
|
buck5: BUCK5 {
|
||||||
|
regulator-name = "buck5";
|
||||||
|
regulator-min-microvolt = <700000>;
|
||||||
|
regulator-max-microvolt = <1350000>;
|
||||||
|
regulator-boot-on;
|
||||||
|
};
|
||||||
|
buck6: BUCK6 {
|
||||||
|
regulator-name = "buck6";
|
||||||
|
regulator-min-microvolt = <3000000>;
|
||||||
|
regulator-max-microvolt = <3300000>;
|
||||||
|
regulator-boot-on;
|
||||||
|
};
|
||||||
|
buck7: BUCK7 {
|
||||||
|
regulator-name = "buck7";
|
||||||
|
regulator-min-microvolt = <1605000>;
|
||||||
|
regulator-max-microvolt = <1995000>;
|
||||||
|
regulator-boot-on;
|
||||||
|
};
|
||||||
|
buck8: BUCK8 {
|
||||||
|
regulator-name = "buck8";
|
||||||
|
regulator-min-microvolt = <800000>;
|
||||||
|
regulator-max-microvolt = <1400000>;
|
||||||
|
};
|
||||||
|
|
||||||
|
ldo1: LDO1 {
|
||||||
|
regulator-name = "ldo1";
|
||||||
|
regulator-min-microvolt = <3000000>;
|
||||||
|
regulator-max-microvolt = <3300000>;
|
||||||
|
regulator-boot-on;
|
||||||
|
};
|
||||||
|
ldo2: LDO2 {
|
||||||
|
regulator-name = "ldo2";
|
||||||
|
regulator-min-microvolt = <900000>;
|
||||||
|
regulator-max-microvolt = <900000>;
|
||||||
|
regulator-boot-on;
|
||||||
|
};
|
||||||
|
ldo3: LDO3 {
|
||||||
|
regulator-name = "ldo3";
|
||||||
|
regulator-min-microvolt = <1800000>;
|
||||||
|
regulator-max-microvolt = <3300000>;
|
||||||
|
};
|
||||||
|
ldo4: LDO4 {
|
||||||
|
regulator-name = "ldo4";
|
||||||
|
regulator-min-microvolt = <900000>;
|
||||||
|
regulator-max-microvolt = <1800000>;
|
||||||
|
};
|
||||||
|
ldo5: LDO5 {
|
||||||
|
regulator-name = "ldo5";
|
||||||
|
regulator-min-microvolt = <1800000>;
|
||||||
|
regulator-max-microvolt = <3300000>;
|
||||||
|
};
|
||||||
|
ldo6: LDO6 {
|
||||||
|
regulator-name = "ldo6";
|
||||||
|
regulator-min-microvolt = <900000>;
|
||||||
|
regulator-max-microvolt = <1800000>;
|
||||||
|
};
|
||||||
|
ldo7_reg: LDO7 {
|
||||||
|
regulator-name = "ldo7";
|
||||||
|
regulator-min-microvolt = <1800000>;
|
||||||
|
regulator-max-microvolt = <3300000>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
|
@ -0,0 +1,222 @@
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: http://devicetree.org/schemas/mfd/rohm,bd71847-pmic.yaml#
|
||||||
|
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||||
|
|
||||||
|
title: ROHM BD71847 and BD71850 Power Management Integrated Circuit bindings
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
|
||||||
|
|
||||||
|
description: |
|
||||||
|
BD71847AMWV and BD71850MWV are programmable Power Management ICs for powering
|
||||||
|
single-core, dual-core, and quad-core SoCs such as NXP-i.MX 8M. It is
|
||||||
|
optimized for low BOM cost and compact solution footprint. BD71847MWV and
|
||||||
|
BD71850MWV integrate 6 Buck regulators and 6 LDOs.
|
||||||
|
Datasheets are available at
|
||||||
|
https://www.rohm.com/products/power-management/power-management-ic-for-system/industrial-consumer-applications/nxp-imx/bd71847amwv-product
|
||||||
|
https://www.rohm.com/products/power-management/power-management-ic-for-system/industrial-consumer-applications/nxp-imx/bd71850mwv-product
|
||||||
|
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
enum:
|
||||||
|
- rohm,bd71847
|
||||||
|
- rohm,bd71850
|
||||||
|
|
||||||
|
reg:
|
||||||
|
description:
|
||||||
|
I2C slave address.
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
interrupts:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
clocks:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
"#clock-cells":
|
||||||
|
const: 0
|
||||||
|
|
||||||
|
# The BD71847 abd BD71850 support two different HW states as reset target
|
||||||
|
# states. States are called as SNVS and READY. At READY state all the PMIC
|
||||||
|
# power outputs go down and OTP is reload. At the SNVS state all other logic
|
||||||
|
# and external devices apart from the SNVS power domain are shut off. Please
|
||||||
|
# refer to NXP i.MX8 documentation for further information regarding SNVS
|
||||||
|
# state. When a reset is done via SNVS state the PMIC OTP data is not reload.
|
||||||
|
# This causes power outputs that have been under SW control to stay down when
|
||||||
|
# reset has switched power state to SNVS. If reset is done via READY state the
|
||||||
|
# power outputs will be returned to HW control by OTP loading. Thus the reset
|
||||||
|
# target state is set to READY by default. If SNVS state is used the boot
|
||||||
|
# crucial regulators must have the regulator-always-on and regulator-boot-on
|
||||||
|
# properties set in regulator node.
|
||||||
|
|
||||||
|
rohm,reset-snvs-powered:
|
||||||
|
description:
|
||||||
|
Transfer PMIC to SNVS state at reset.
|
||||||
|
type: boolean
|
||||||
|
|
||||||
|
# Configure the "short press" and "long press" timers for the power button.
|
||||||
|
# Values are rounded to what hardware supports
|
||||||
|
# Short-press:
|
||||||
|
# Shortest being 10ms, next 500ms and then multiple of 500ms up to 7,5s
|
||||||
|
# Long-press:
|
||||||
|
# Shortest being 10ms, next 1000ms and then multiple of 1000ms up to 15s
|
||||||
|
# If these properties are not present the existing # configuration (from
|
||||||
|
# bootloader or OTP) is not touched.
|
||||||
|
|
||||||
|
rohm,short-press-ms:
|
||||||
|
description:
|
||||||
|
Short press duration in milliseconds
|
||||||
|
enum:
|
||||||
|
- 10
|
||||||
|
- 500
|
||||||
|
- 1000
|
||||||
|
- 1500
|
||||||
|
- 2000
|
||||||
|
- 2500
|
||||||
|
- 3000
|
||||||
|
- 3500
|
||||||
|
- 4000
|
||||||
|
- 4500
|
||||||
|
- 5000
|
||||||
|
- 5500
|
||||||
|
- 6000
|
||||||
|
- 6500
|
||||||
|
- 7000
|
||||||
|
- 7500
|
||||||
|
|
||||||
|
rohm,long-press-ms:
|
||||||
|
description:
|
||||||
|
Long press duration in milliseconds
|
||||||
|
enum:
|
||||||
|
- 10
|
||||||
|
- 1000
|
||||||
|
- 2000
|
||||||
|
- 3000
|
||||||
|
- 4000
|
||||||
|
- 5000
|
||||||
|
- 6000
|
||||||
|
- 7000
|
||||||
|
- 8000
|
||||||
|
- 9000
|
||||||
|
- 10000
|
||||||
|
- 11000
|
||||||
|
- 12000
|
||||||
|
- 13000
|
||||||
|
- 14000
|
||||||
|
- 15000
|
||||||
|
|
||||||
|
regulators:
|
||||||
|
$ref: ../regulator/rohm,bd71847-regulator.yaml
|
||||||
|
description:
|
||||||
|
List of child nodes that specify the regulators.
|
||||||
|
|
||||||
|
required:
|
||||||
|
- compatible
|
||||||
|
- reg
|
||||||
|
- interrupts
|
||||||
|
- clocks
|
||||||
|
- "#clock-cells"
|
||||||
|
- regulators
|
||||||
|
|
||||||
|
additionalProperties: false
|
||||||
|
|
||||||
|
examples:
|
||||||
|
- |
|
||||||
|
#include <dt-bindings/interrupt-controller/irq.h>
|
||||||
|
#include <dt-bindings/leds/common.h>
|
||||||
|
|
||||||
|
i2c {
|
||||||
|
pmic: pmic@4b {
|
||||||
|
compatible = "rohm,bd71847";
|
||||||
|
reg = <0x4b>;
|
||||||
|
interrupt-parent = <&gpio1>;
|
||||||
|
interrupts = <29 IRQ_TYPE_LEVEL_LOW>;
|
||||||
|
#clock-cells = <0>;
|
||||||
|
clocks = <&osc 0>;
|
||||||
|
rohm,reset-snvs-powered;
|
||||||
|
rohm,short-press-ms = <10>;
|
||||||
|
rohm,long-press-ms = <2000>;
|
||||||
|
|
||||||
|
regulators {
|
||||||
|
buck1: BUCK1 {
|
||||||
|
regulator-name = "buck1";
|
||||||
|
regulator-min-microvolt = <700000>;
|
||||||
|
regulator-max-microvolt = <1300000>;
|
||||||
|
regulator-boot-on;
|
||||||
|
regulator-always-on;
|
||||||
|
regulator-ramp-delay = <1250>;
|
||||||
|
rohm,dvs-run-voltage = <900000>;
|
||||||
|
rohm,dvs-idle-voltage = <850000>;
|
||||||
|
rohm,dvs-suspend-voltage = <800000>;
|
||||||
|
};
|
||||||
|
buck2: BUCK2 {
|
||||||
|
regulator-name = "buck2";
|
||||||
|
regulator-min-microvolt = <700000>;
|
||||||
|
regulator-max-microvolt = <1300000>;
|
||||||
|
regulator-boot-on;
|
||||||
|
regulator-always-on;
|
||||||
|
regulator-ramp-delay = <1250>;
|
||||||
|
rohm,dvs-run-voltage = <1000000>;
|
||||||
|
rohm,dvs-idle-voltage = <900000>;
|
||||||
|
};
|
||||||
|
buck3: BUCK3 {
|
||||||
|
regulator-name = "buck3";
|
||||||
|
regulator-min-microvolt = <550000>;
|
||||||
|
regulator-max-microvolt = <1350000>;
|
||||||
|
regulator-boot-on;
|
||||||
|
};
|
||||||
|
buck4: BUCK4 {
|
||||||
|
regulator-name = "buck4";
|
||||||
|
regulator-min-microvolt = <2600000>;
|
||||||
|
regulator-max-microvolt = <3300000>;
|
||||||
|
regulator-boot-on;
|
||||||
|
};
|
||||||
|
buck5: BUCK5 {
|
||||||
|
regulator-name = "buck5";
|
||||||
|
regulator-min-microvolt = <1605000>;
|
||||||
|
regulator-max-microvolt = <1995000>;
|
||||||
|
regulator-boot-on;
|
||||||
|
};
|
||||||
|
buck8: BUCK6 {
|
||||||
|
regulator-name = "buck6";
|
||||||
|
regulator-min-microvolt = <800000>;
|
||||||
|
regulator-max-microvolt = <1400000>;
|
||||||
|
};
|
||||||
|
|
||||||
|
ldo1: LDO1 {
|
||||||
|
regulator-name = "ldo1";
|
||||||
|
regulator-min-microvolt = <1600000>;
|
||||||
|
regulator-max-microvolt = <3300000>;
|
||||||
|
regulator-boot-on;
|
||||||
|
};
|
||||||
|
ldo2: LDO2 {
|
||||||
|
regulator-name = "ldo2";
|
||||||
|
regulator-min-microvolt = <800000>;
|
||||||
|
regulator-max-microvolt = <900000>;
|
||||||
|
regulator-boot-on;
|
||||||
|
};
|
||||||
|
ldo3: LDO3 {
|
||||||
|
regulator-name = "ldo3";
|
||||||
|
regulator-min-microvolt = <1800000>;
|
||||||
|
regulator-max-microvolt = <3300000>;
|
||||||
|
};
|
||||||
|
ldo4: LDO4 {
|
||||||
|
regulator-name = "ldo4";
|
||||||
|
regulator-min-microvolt = <900000>;
|
||||||
|
regulator-max-microvolt = <1800000>;
|
||||||
|
};
|
||||||
|
ldo5: LDO5 {
|
||||||
|
regulator-name = "ldo5";
|
||||||
|
regulator-min-microvolt = <800000>;
|
||||||
|
regulator-max-microvolt = <3300000>;
|
||||||
|
};
|
||||||
|
ldo6: LDO6 {
|
||||||
|
regulator-name = "ldo6";
|
||||||
|
regulator-min-microvolt = <900000>;
|
||||||
|
regulator-max-microvolt = <1800000>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
|
@ -39,6 +39,8 @@ properties:
|
||||||
"#size-cells":
|
"#size-cells":
|
||||||
const: 0
|
const: 0
|
||||||
|
|
||||||
|
wakeup-source: true
|
||||||
|
|
||||||
pwm:
|
pwm:
|
||||||
type: object
|
type: object
|
||||||
|
|
||||||
|
@ -81,6 +83,16 @@ patternProperties:
|
||||||
required:
|
required:
|
||||||
- compatible
|
- compatible
|
||||||
|
|
||||||
|
timer:
|
||||||
|
type: object
|
||||||
|
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
const: st,stm32-lptimer-timer
|
||||||
|
|
||||||
|
required:
|
||||||
|
- compatible
|
||||||
|
|
||||||
required:
|
required:
|
||||||
- "#address-cells"
|
- "#address-cells"
|
||||||
- "#size-cells"
|
- "#size-cells"
|
||||||
|
@ -115,6 +127,10 @@ examples:
|
||||||
counter {
|
counter {
|
||||||
compatible = "st,stm32-lptimer-counter";
|
compatible = "st,stm32-lptimer-counter";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
timer {
|
||||||
|
compatible = "st,stm32-lptimer-timer";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
...
|
...
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: http://devicetree.org/schemas/pwm/iqs620a-pwm.yaml#
|
||||||
|
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||||
|
|
||||||
|
title: Azoteq IQS620A PWM Generator
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Jeff LaBundy <jeff@labundy.com>
|
||||||
|
|
||||||
|
description: |
|
||||||
|
The Azoteq IQS620A multi-function sensor generates a fixed-frequency PWM
|
||||||
|
output represented by a "pwm" child node from the parent MFD driver. See
|
||||||
|
Documentation/devicetree/bindings/mfd/iqs62x.yaml for further details as
|
||||||
|
well as an example.
|
||||||
|
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
enum:
|
||||||
|
- azoteq,iqs620a-pwm
|
||||||
|
|
||||||
|
"#pwm-cells":
|
||||||
|
const: 2
|
||||||
|
|
||||||
|
required:
|
||||||
|
- compatible
|
||||||
|
- "#pwm-cells"
|
||||||
|
|
||||||
|
additionalProperties: false
|
||||||
|
|
||||||
|
...
|
|
@ -1,162 +0,0 @@
|
||||||
ROHM BD71837 and BD71847 Power Management Integrated Circuit regulator bindings
|
|
||||||
|
|
||||||
Required properties:
|
|
||||||
- regulator-name: should be "buck1", ..., "buck8" and "ldo1", ..., "ldo7" for
|
|
||||||
BD71837. For BD71847 names should be "buck1", ..., "buck6"
|
|
||||||
and "ldo1", ..., "ldo6"
|
|
||||||
|
|
||||||
List of regulators provided by this controller. BD71837 regulators node
|
|
||||||
should be sub node of the BD71837 MFD node. See BD71837 MFD bindings at
|
|
||||||
Documentation/devicetree/bindings/mfd/rohm,bd71837-pmic.txt
|
|
||||||
Regulator nodes should be named to BUCK_<number> and LDO_<number>. The
|
|
||||||
definition for each of these nodes is defined using the standard
|
|
||||||
binding for regulators at
|
|
||||||
Documentation/devicetree/bindings/regulator/regulator.txt.
|
|
||||||
Note that if BD71837 starts at RUN state you probably want to use
|
|
||||||
regulator-boot-on at least for BUCK6 and BUCK7 so that those are not
|
|
||||||
disabled by driver at startup. LDO5 and LDO6 are supplied by those and
|
|
||||||
if they are disabled at startup the voltage monitoring for LDO5/LDO6 will
|
|
||||||
cause PMIC to reset.
|
|
||||||
|
|
||||||
The valid names for BD71837 regulator nodes are:
|
|
||||||
BUCK1, BUCK2, BUCK3, BUCK4, BUCK5, BUCK6, BUCK7, BUCK8
|
|
||||||
LDO1, LDO2, LDO3, LDO4, LDO5, LDO6, LDO7
|
|
||||||
|
|
||||||
The valid names for BD71847 regulator nodes are:
|
|
||||||
BUCK1, BUCK2, BUCK3, BUCK4, BUCK5, BUCK6
|
|
||||||
LDO1, LDO2, LDO3, LDO4, LDO5, LDO6
|
|
||||||
|
|
||||||
Optional properties:
|
|
||||||
- rohm,dvs-run-voltage : PMIC default "RUN" state voltage in uV.
|
|
||||||
See below table for bucks which support this.
|
|
||||||
- rohm,dvs-idle-voltage : PMIC default "IDLE" state voltage in uV.
|
|
||||||
See below table for bucks which support this.
|
|
||||||
- rohm,dvs-suspend-voltage : PMIC default "SUSPEND" state voltage in uV.
|
|
||||||
See below table for bucks which support this.
|
|
||||||
- Any optional property defined in bindings/regulator/regulator.txt
|
|
||||||
|
|
||||||
Supported default DVS states:
|
|
||||||
|
|
||||||
BD71837:
|
|
||||||
buck | dvs-run-voltage | dvs-idle-voltage | dvs-suspend-voltage
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
1 | supported | supported | supported
|
|
||||||
----------------------------------------------------------------------------
|
|
||||||
2 | supported | supported | not supported
|
|
||||||
----------------------------------------------------------------------------
|
|
||||||
3 | supported | not supported | not supported
|
|
||||||
----------------------------------------------------------------------------
|
|
||||||
4 | supported | not supported | not supported
|
|
||||||
----------------------------------------------------------------------------
|
|
||||||
rest | not supported | not supported | not supported
|
|
||||||
|
|
||||||
BD71847:
|
|
||||||
buck | dvs-run-voltage | dvs-idle-voltage | dvs-suspend-voltage
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
1 | supported | supported | supported
|
|
||||||
----------------------------------------------------------------------------
|
|
||||||
2 | supported | supported | not supported
|
|
||||||
----------------------------------------------------------------------------
|
|
||||||
rest | not supported | not supported | not supported
|
|
||||||
|
|
||||||
Example:
|
|
||||||
regulators {
|
|
||||||
buck1: BUCK1 {
|
|
||||||
regulator-name = "buck1";
|
|
||||||
regulator-min-microvolt = <700000>;
|
|
||||||
regulator-max-microvolt = <1300000>;
|
|
||||||
regulator-boot-on;
|
|
||||||
regulator-always-on;
|
|
||||||
regulator-ramp-delay = <1250>;
|
|
||||||
rohm,dvs-run-voltage = <900000>;
|
|
||||||
rohm,dvs-idle-voltage = <850000>;
|
|
||||||
rohm,dvs-suspend-voltage = <800000>;
|
|
||||||
};
|
|
||||||
buck2: BUCK2 {
|
|
||||||
regulator-name = "buck2";
|
|
||||||
regulator-min-microvolt = <700000>;
|
|
||||||
regulator-max-microvolt = <1300000>;
|
|
||||||
regulator-boot-on;
|
|
||||||
regulator-always-on;
|
|
||||||
regulator-ramp-delay = <1250>;
|
|
||||||
rohm,dvs-run-voltage = <1000000>;
|
|
||||||
rohm,dvs-idle-voltage = <900000>;
|
|
||||||
};
|
|
||||||
buck3: BUCK3 {
|
|
||||||
regulator-name = "buck3";
|
|
||||||
regulator-min-microvolt = <700000>;
|
|
||||||
regulator-max-microvolt = <1300000>;
|
|
||||||
regulator-boot-on;
|
|
||||||
rohm,dvs-run-voltage = <1000000>;
|
|
||||||
};
|
|
||||||
buck4: BUCK4 {
|
|
||||||
regulator-name = "buck4";
|
|
||||||
regulator-min-microvolt = <700000>;
|
|
||||||
regulator-max-microvolt = <1300000>;
|
|
||||||
regulator-boot-on;
|
|
||||||
rohm,dvs-run-voltage = <1000000>;
|
|
||||||
};
|
|
||||||
buck5: BUCK5 {
|
|
||||||
regulator-name = "buck5";
|
|
||||||
regulator-min-microvolt = <700000>;
|
|
||||||
regulator-max-microvolt = <1350000>;
|
|
||||||
regulator-boot-on;
|
|
||||||
};
|
|
||||||
buck6: BUCK6 {
|
|
||||||
regulator-name = "buck6";
|
|
||||||
regulator-min-microvolt = <3000000>;
|
|
||||||
regulator-max-microvolt = <3300000>;
|
|
||||||
regulator-boot-on;
|
|
||||||
};
|
|
||||||
buck7: BUCK7 {
|
|
||||||
regulator-name = "buck7";
|
|
||||||
regulator-min-microvolt = <1605000>;
|
|
||||||
regulator-max-microvolt = <1995000>;
|
|
||||||
regulator-boot-on;
|
|
||||||
};
|
|
||||||
buck8: BUCK8 {
|
|
||||||
regulator-name = "buck8";
|
|
||||||
regulator-min-microvolt = <800000>;
|
|
||||||
regulator-max-microvolt = <1400000>;
|
|
||||||
};
|
|
||||||
|
|
||||||
ldo1: LDO1 {
|
|
||||||
regulator-name = "ldo1";
|
|
||||||
regulator-min-microvolt = <3000000>;
|
|
||||||
regulator-max-microvolt = <3300000>;
|
|
||||||
regulator-boot-on;
|
|
||||||
};
|
|
||||||
ldo2: LDO2 {
|
|
||||||
regulator-name = "ldo2";
|
|
||||||
regulator-min-microvolt = <900000>;
|
|
||||||
regulator-max-microvolt = <900000>;
|
|
||||||
regulator-boot-on;
|
|
||||||
};
|
|
||||||
ldo3: LDO3 {
|
|
||||||
regulator-name = "ldo3";
|
|
||||||
regulator-min-microvolt = <1800000>;
|
|
||||||
regulator-max-microvolt = <3300000>;
|
|
||||||
};
|
|
||||||
ldo4: LDO4 {
|
|
||||||
regulator-name = "ldo4";
|
|
||||||
regulator-min-microvolt = <900000>;
|
|
||||||
regulator-max-microvolt = <1800000>;
|
|
||||||
};
|
|
||||||
ldo5: LDO5 {
|
|
||||||
regulator-name = "ldo5";
|
|
||||||
regulator-min-microvolt = <1800000>;
|
|
||||||
regulator-max-microvolt = <3300000>;
|
|
||||||
};
|
|
||||||
ldo6: LDO6 {
|
|
||||||
regulator-name = "ldo6";
|
|
||||||
regulator-min-microvolt = <900000>;
|
|
||||||
regulator-max-microvolt = <1800000>;
|
|
||||||
};
|
|
||||||
ldo7_reg: LDO7 {
|
|
||||||
regulator-name = "ldo7";
|
|
||||||
regulator-min-microvolt = <1800000>;
|
|
||||||
regulator-max-microvolt = <3300000>;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,103 @@
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: http://devicetree.org/schemas/regulator/rohm,bd71837-regulator.yaml#
|
||||||
|
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||||
|
|
||||||
|
title: ROHM BD71837 Power Management Integrated Circuit regulators
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
|
||||||
|
|
||||||
|
description: |
|
||||||
|
List of regulators provided by this controller. BD71837 regulators node
|
||||||
|
should be sub node of the BD71837 MFD node. See BD71837 MFD bindings at
|
||||||
|
Documentation/devicetree/bindings/mfd/rohm,bd71837-pmic.yaml
|
||||||
|
Regulator nodes should be named to BUCK_<number> and LDO_<number>. The
|
||||||
|
definition for each of these nodes is defined using the standard
|
||||||
|
binding for regulators at
|
||||||
|
Documentation/devicetree/bindings/regulator/regulator.txt.
|
||||||
|
Note that if BD71837 starts at RUN state you probably want to use
|
||||||
|
regulator-boot-on at least for BUCK6 and BUCK7 so that those are not
|
||||||
|
disabled by driver at startup. LDO5 and LDO6 are supplied by those and
|
||||||
|
if they are disabled at startup the voltage monitoring for LDO5/LDO6 will
|
||||||
|
cause PMIC to reset.
|
||||||
|
|
||||||
|
#The valid names for BD71837 regulator nodes are:
|
||||||
|
#BUCK1, BUCK2, BUCK3, BUCK4, BUCK5, BUCK6, BUCK7, BUCK8
|
||||||
|
#LDO1, LDO2, LDO3, LDO4, LDO5, LDO6, LDO7
|
||||||
|
|
||||||
|
patternProperties:
|
||||||
|
"^LDO[1-7]$":
|
||||||
|
type: object
|
||||||
|
allOf:
|
||||||
|
- $ref: regulator.yaml#
|
||||||
|
description:
|
||||||
|
Properties for single LDO regulator.
|
||||||
|
|
||||||
|
properties:
|
||||||
|
regulator-name:
|
||||||
|
pattern: "^ldo[1-7]$"
|
||||||
|
description:
|
||||||
|
should be "ldo1", ..., "ldo7"
|
||||||
|
|
||||||
|
"^BUCK[1-8]$":
|
||||||
|
type: object
|
||||||
|
allOf:
|
||||||
|
- $ref: regulator.yaml#
|
||||||
|
description:
|
||||||
|
Properties for single BUCK regulator.
|
||||||
|
|
||||||
|
properties:
|
||||||
|
regulator-name:
|
||||||
|
pattern: "^buck[1-8]$"
|
||||||
|
description:
|
||||||
|
should be "buck1", ..., "buck8"
|
||||||
|
|
||||||
|
rohm,dvs-run-voltage:
|
||||||
|
allOf:
|
||||||
|
- $ref: "/schemas/types.yaml#/definitions/uint32"
|
||||||
|
- minimum: 0
|
||||||
|
maximum: 1300000
|
||||||
|
description:
|
||||||
|
PMIC default "RUN" state voltage in uV. See below table for
|
||||||
|
bucks which support this. 0 means disabled.
|
||||||
|
|
||||||
|
rohm,dvs-idle-voltage:
|
||||||
|
allOf:
|
||||||
|
- $ref: "/schemas/types.yaml#/definitions/uint32"
|
||||||
|
- minimum: 0
|
||||||
|
maximum: 1300000
|
||||||
|
description:
|
||||||
|
PMIC default "IDLE" state voltage in uV. See below table for
|
||||||
|
bucks which support this. 0 means disabled.
|
||||||
|
|
||||||
|
rohm,dvs-suspend-voltage:
|
||||||
|
allOf:
|
||||||
|
- $ref: "/schemas/types.yaml#/definitions/uint32"
|
||||||
|
- minimum: 0
|
||||||
|
maximum: 1300000
|
||||||
|
description:
|
||||||
|
PMIC default "SUSPEND" state voltage in uV. See below table for
|
||||||
|
bucks which support this. 0 means disabled.
|
||||||
|
|
||||||
|
# Supported default DVS states:
|
||||||
|
#
|
||||||
|
# BD71837:
|
||||||
|
# buck | dvs-run-voltage | dvs-idle-voltage | dvs-suspend-voltage
|
||||||
|
# ----------------------------------------------------------------
|
||||||
|
# 1 | supported | supported | supported
|
||||||
|
# ----------------------------------------------------------------
|
||||||
|
# 2 | supported | supported | not supported
|
||||||
|
# ----------------------------------------------------------------
|
||||||
|
# 3 | supported | not supported | not supported
|
||||||
|
# ----------------------------------------------------------------
|
||||||
|
# 4 | supported | not supported | not supported
|
||||||
|
# ----------------------------------------------------------------
|
||||||
|
# rest | not supported | not supported | not supported
|
||||||
|
|
||||||
|
|
||||||
|
required:
|
||||||
|
- regulator-name
|
||||||
|
additionalProperties: false
|
||||||
|
additionalProperties: false
|
|
@ -0,0 +1,97 @@
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: http://devicetree.org/schemas/regulator/rohm,bd71847-regulator.yaml#
|
||||||
|
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||||
|
|
||||||
|
title: ROHM BD71847 and BD71850 Power Management Integrated Circuit regulators
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
|
||||||
|
|
||||||
|
description: |
|
||||||
|
List of regulators provided by this controller. BD71847 regulators node
|
||||||
|
should be sub node of the BD71847 MFD node. See BD71847 MFD bindings at
|
||||||
|
Documentation/devicetree/bindings/mfd/rohm,bd71847-pmic.yaml
|
||||||
|
Regulator nodes should be named to BUCK_<number> and LDO_<number>. The
|
||||||
|
definition for each of these nodes is defined using the standard
|
||||||
|
binding for regulators at
|
||||||
|
Documentation/devicetree/bindings/regulator/regulator.txt.
|
||||||
|
Note that if BD71847 starts at RUN state you probably want to use
|
||||||
|
regulator-boot-on at least for BUCK5. LDO6 is supplied by it and it must
|
||||||
|
not be disabled by driver at startup. If BUCK5 is disabled at startup the
|
||||||
|
voltage monitoring for LDO5/LDO6 can cause PMIC to reset.
|
||||||
|
|
||||||
|
#The valid names for BD71847 regulator nodes are:
|
||||||
|
#BUCK1, BUCK2, BUCK3, BUCK4, BUCK5, BUCK6
|
||||||
|
#LDO1, LDO2, LDO3, LDO4, LDO5, LDO6
|
||||||
|
|
||||||
|
patternProperties:
|
||||||
|
"^LDO[1-6]$":
|
||||||
|
type: object
|
||||||
|
allOf:
|
||||||
|
- $ref: regulator.yaml#
|
||||||
|
description:
|
||||||
|
Properties for single LDO regulator.
|
||||||
|
|
||||||
|
properties:
|
||||||
|
regulator-name:
|
||||||
|
pattern: "^ldo[1-6]$"
|
||||||
|
description:
|
||||||
|
should be "ldo1", ..., "ldo6"
|
||||||
|
|
||||||
|
"^BUCK[1-6]$":
|
||||||
|
type: object
|
||||||
|
allOf:
|
||||||
|
- $ref: regulator.yaml#
|
||||||
|
description:
|
||||||
|
Properties for single BUCK regulator.
|
||||||
|
|
||||||
|
properties:
|
||||||
|
regulator-name:
|
||||||
|
pattern: "^buck[1-6]$"
|
||||||
|
description:
|
||||||
|
should be "buck1", ..., "buck6"
|
||||||
|
|
||||||
|
rohm,dvs-run-voltage:
|
||||||
|
allOf:
|
||||||
|
- $ref: "/schemas/types.yaml#/definitions/uint32"
|
||||||
|
- minimum: 0
|
||||||
|
maximum: 1300000
|
||||||
|
description:
|
||||||
|
PMIC default "RUN" state voltage in uV. See below table for
|
||||||
|
bucks which support this. 0 means disabled.
|
||||||
|
|
||||||
|
rohm,dvs-idle-voltage:
|
||||||
|
allOf:
|
||||||
|
- $ref: "/schemas/types.yaml#/definitions/uint32"
|
||||||
|
- minimum: 0
|
||||||
|
maximum: 1300000
|
||||||
|
description:
|
||||||
|
PMIC default "IDLE" state voltage in uV. See below table for
|
||||||
|
bucks which support this. 0 means disabled.
|
||||||
|
|
||||||
|
rohm,dvs-suspend-voltage:
|
||||||
|
allOf:
|
||||||
|
- $ref: "/schemas/types.yaml#/definitions/uint32"
|
||||||
|
- minimum: 0
|
||||||
|
maximum: 1300000
|
||||||
|
description:
|
||||||
|
PMIC default "SUSPEND" state voltage in uV. See below table for
|
||||||
|
bucks which support this. 0 means disabled.
|
||||||
|
|
||||||
|
# Supported default DVS states:
|
||||||
|
#
|
||||||
|
# BD71847:
|
||||||
|
# buck | dvs-run-voltage | dvs-idle-voltage | dvs-suspend-voltage
|
||||||
|
# ----------------------------------------------------------------
|
||||||
|
# 1 | supported | supported | supported
|
||||||
|
# ----------------------------------------------------------------
|
||||||
|
# 2 | supported | supported | not supported
|
||||||
|
# ----------------------------------------------------------------
|
||||||
|
# rest | not supported | not supported | not supported
|
||||||
|
|
||||||
|
required:
|
||||||
|
- regulator-name
|
||||||
|
additionalProperties: false
|
||||||
|
additionalProperties: false
|
|
@ -88,6 +88,7 @@ source "drivers/iio/orientation/Kconfig"
|
||||||
if IIO_TRIGGER
|
if IIO_TRIGGER
|
||||||
source "drivers/iio/trigger/Kconfig"
|
source "drivers/iio/trigger/Kconfig"
|
||||||
endif #IIO_TRIGGER
|
endif #IIO_TRIGGER
|
||||||
|
source "drivers/iio/position/Kconfig"
|
||||||
source "drivers/iio/potentiometer/Kconfig"
|
source "drivers/iio/potentiometer/Kconfig"
|
||||||
source "drivers/iio/potentiostat/Kconfig"
|
source "drivers/iio/potentiostat/Kconfig"
|
||||||
source "drivers/iio/pressure/Kconfig"
|
source "drivers/iio/pressure/Kconfig"
|
||||||
|
|
|
@ -31,6 +31,7 @@ obj-y += light/
|
||||||
obj-y += magnetometer/
|
obj-y += magnetometer/
|
||||||
obj-y += multiplexer/
|
obj-y += multiplexer/
|
||||||
obj-y += orientation/
|
obj-y += orientation/
|
||||||
|
obj-y += position/
|
||||||
obj-y += potentiometer/
|
obj-y += potentiometer/
|
||||||
obj-y += potentiostat/
|
obj-y += potentiostat/
|
||||||
obj-y += pressure/
|
obj-y += pressure/
|
||||||
|
|
|
@ -795,6 +795,16 @@ config RCAR_GYRO_ADC
|
||||||
To compile this driver as a module, choose M here: the
|
To compile this driver as a module, choose M here: the
|
||||||
module will be called rcar-gyroadc.
|
module will be called rcar-gyroadc.
|
||||||
|
|
||||||
|
config RN5T618_ADC
|
||||||
|
tristate "ADC for the RN5T618/RC5T619 family of chips"
|
||||||
|
depends on MFD_RN5T618
|
||||||
|
help
|
||||||
|
Say yes here to build support for the integrated ADC inside the
|
||||||
|
RN5T618/619 series PMICs:
|
||||||
|
|
||||||
|
This driver can also be built as a module. If so, the module
|
||||||
|
will be called rn5t618-adc.
|
||||||
|
|
||||||
config ROCKCHIP_SARADC
|
config ROCKCHIP_SARADC
|
||||||
tristate "Rockchip SARADC driver"
|
tristate "Rockchip SARADC driver"
|
||||||
depends on ARCH_ROCKCHIP || (ARM && COMPILE_TEST)
|
depends on ARCH_ROCKCHIP || (ARM && COMPILE_TEST)
|
||||||
|
|
|
@ -75,6 +75,7 @@ obj-$(CONFIG_QCOM_VADC_COMMON) += qcom-vadc-common.o
|
||||||
obj-$(CONFIG_QCOM_SPMI_VADC) += qcom-spmi-vadc.o
|
obj-$(CONFIG_QCOM_SPMI_VADC) += qcom-spmi-vadc.o
|
||||||
obj-$(CONFIG_QCOM_PM8XXX_XOADC) += qcom-pm8xxx-xoadc.o
|
obj-$(CONFIG_QCOM_PM8XXX_XOADC) += qcom-pm8xxx-xoadc.o
|
||||||
obj-$(CONFIG_RCAR_GYRO_ADC) += rcar-gyroadc.o
|
obj-$(CONFIG_RCAR_GYRO_ADC) += rcar-gyroadc.o
|
||||||
|
obj-$(CONFIG_RN5T618_ADC) += rn5t618-adc.o
|
||||||
obj-$(CONFIG_ROCKCHIP_SARADC) += rockchip_saradc.o
|
obj-$(CONFIG_ROCKCHIP_SARADC) += rockchip_saradc.o
|
||||||
obj-$(CONFIG_SC27XX_ADC) += sc27xx_adc.o
|
obj-$(CONFIG_SC27XX_ADC) += sc27xx_adc.o
|
||||||
obj-$(CONFIG_SPEAR_ADC) += spear_adc.o
|
obj-$(CONFIG_SPEAR_ADC) += spear_adc.o
|
||||||
|
|
|
@ -0,0 +1,256 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
|
/*
|
||||||
|
* ADC driver for the RICOH RN5T618 power management chip family
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019 Andreas Kemnade
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/device.h>
|
||||||
|
#include <linux/errno.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/mfd/rn5t618.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/completion.h>
|
||||||
|
#include <linux/regmap.h>
|
||||||
|
#include <linux/iio/iio.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
|
||||||
|
#define RN5T618_ADC_CONVERSION_TIMEOUT (msecs_to_jiffies(500))
|
||||||
|
#define RN5T618_REFERENCE_VOLT 2500
|
||||||
|
|
||||||
|
/* mask for selecting channels for single conversion */
|
||||||
|
#define RN5T618_ADCCNT3_CHANNEL_MASK 0x7
|
||||||
|
/* average 4-time conversion mode */
|
||||||
|
#define RN5T618_ADCCNT3_AVG BIT(3)
|
||||||
|
/* set for starting a single conversion, gets cleared by hw when done */
|
||||||
|
#define RN5T618_ADCCNT3_GODONE BIT(4)
|
||||||
|
/* automatic conversion, period is in ADCCNT2, selected channels are
|
||||||
|
* in ADCCNT1
|
||||||
|
*/
|
||||||
|
#define RN5T618_ADCCNT3_AUTO BIT(5)
|
||||||
|
#define RN5T618_ADCEND_IRQ BIT(0)
|
||||||
|
|
||||||
|
struct rn5t618_adc_data {
|
||||||
|
struct device *dev;
|
||||||
|
struct rn5t618 *rn5t618;
|
||||||
|
struct completion conv_completion;
|
||||||
|
int irq;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rn5t618_channel_ratios {
|
||||||
|
u16 numerator;
|
||||||
|
u16 denominator;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum rn5t618_channels {
|
||||||
|
LIMMON = 0,
|
||||||
|
VBAT,
|
||||||
|
VADP,
|
||||||
|
VUSB,
|
||||||
|
VSYS,
|
||||||
|
VTHM,
|
||||||
|
AIN1,
|
||||||
|
AIN0
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct rn5t618_channel_ratios rn5t618_ratios[8] = {
|
||||||
|
[LIMMON] = {50, 32}, /* measured across 20mOhm, amplified by 32 */
|
||||||
|
[VBAT] = {2, 1},
|
||||||
|
[VADP] = {3, 1},
|
||||||
|
[VUSB] = {3, 1},
|
||||||
|
[VSYS] = {3, 1},
|
||||||
|
[VTHM] = {1, 1},
|
||||||
|
[AIN1] = {1, 1},
|
||||||
|
[AIN0] = {1, 1},
|
||||||
|
};
|
||||||
|
|
||||||
|
static int rn5t618_read_adc_reg(struct rn5t618 *rn5t618, int reg, u16 *val)
|
||||||
|
{
|
||||||
|
u8 data[2];
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = regmap_bulk_read(rn5t618->regmap, reg, data, sizeof(data));
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
*val = (data[0] << 4) | (data[1] & 0xF);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static irqreturn_t rn5t618_adc_irq(int irq, void *data)
|
||||||
|
{
|
||||||
|
struct rn5t618_adc_data *adc = data;
|
||||||
|
unsigned int r = 0;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* clear low & high threshold irqs */
|
||||||
|
regmap_write(adc->rn5t618->regmap, RN5T618_IR_ADC1, 0);
|
||||||
|
regmap_write(adc->rn5t618->regmap, RN5T618_IR_ADC2, 0);
|
||||||
|
|
||||||
|
ret = regmap_read(adc->rn5t618->regmap, RN5T618_IR_ADC3, &r);
|
||||||
|
if (ret < 0)
|
||||||
|
dev_err(adc->dev, "failed to read IRQ status: %d\n", ret);
|
||||||
|
|
||||||
|
regmap_write(adc->rn5t618->regmap, RN5T618_IR_ADC3, 0);
|
||||||
|
|
||||||
|
if (r & RN5T618_ADCEND_IRQ)
|
||||||
|
complete(&adc->conv_completion);
|
||||||
|
|
||||||
|
return IRQ_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rn5t618_adc_read(struct iio_dev *iio_dev,
|
||||||
|
const struct iio_chan_spec *chan,
|
||||||
|
int *val, int *val2, long mask)
|
||||||
|
{
|
||||||
|
struct rn5t618_adc_data *adc = iio_priv(iio_dev);
|
||||||
|
u16 raw;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (mask == IIO_CHAN_INFO_SCALE) {
|
||||||
|
*val = RN5T618_REFERENCE_VOLT *
|
||||||
|
rn5t618_ratios[chan->channel].numerator;
|
||||||
|
*val2 = rn5t618_ratios[chan->channel].denominator * 4095;
|
||||||
|
|
||||||
|
return IIO_VAL_FRACTIONAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* select channel */
|
||||||
|
ret = regmap_update_bits(adc->rn5t618->regmap, RN5T618_ADCCNT3,
|
||||||
|
RN5T618_ADCCNT3_CHANNEL_MASK,
|
||||||
|
chan->channel);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = regmap_write(adc->rn5t618->regmap, RN5T618_EN_ADCIR3,
|
||||||
|
RN5T618_ADCEND_IRQ);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = regmap_update_bits(adc->rn5t618->regmap, RN5T618_ADCCNT3,
|
||||||
|
RN5T618_ADCCNT3_AVG,
|
||||||
|
mask == IIO_CHAN_INFO_AVERAGE_RAW ?
|
||||||
|
RN5T618_ADCCNT3_AVG : 0);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
init_completion(&adc->conv_completion);
|
||||||
|
/* single conversion */
|
||||||
|
ret = regmap_update_bits(adc->rn5t618->regmap, RN5T618_ADCCNT3,
|
||||||
|
RN5T618_ADCCNT3_GODONE,
|
||||||
|
RN5T618_ADCCNT3_GODONE);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = wait_for_completion_timeout(&adc->conv_completion,
|
||||||
|
RN5T618_ADC_CONVERSION_TIMEOUT);
|
||||||
|
if (ret == 0) {
|
||||||
|
dev_warn(adc->dev, "timeout waiting for adc result\n");
|
||||||
|
return -ETIMEDOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = rn5t618_read_adc_reg(adc->rn5t618,
|
||||||
|
RN5T618_ILIMDATAH + 2 * chan->channel,
|
||||||
|
&raw);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
*val = raw;
|
||||||
|
|
||||||
|
return IIO_VAL_INT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct iio_info rn5t618_adc_iio_info = {
|
||||||
|
.read_raw = &rn5t618_adc_read,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define RN5T618_ADC_CHANNEL(_channel, _type, _name) { \
|
||||||
|
.type = _type, \
|
||||||
|
.channel = _channel, \
|
||||||
|
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
|
||||||
|
BIT(IIO_CHAN_INFO_AVERAGE_RAW) | \
|
||||||
|
BIT(IIO_CHAN_INFO_SCALE), \
|
||||||
|
.datasheet_name = _name, \
|
||||||
|
.indexed = 1. \
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct iio_chan_spec rn5t618_adc_iio_channels[] = {
|
||||||
|
RN5T618_ADC_CHANNEL(LIMMON, IIO_CURRENT, "LIMMON"),
|
||||||
|
RN5T618_ADC_CHANNEL(VBAT, IIO_VOLTAGE, "VBAT"),
|
||||||
|
RN5T618_ADC_CHANNEL(VADP, IIO_VOLTAGE, "VADP"),
|
||||||
|
RN5T618_ADC_CHANNEL(VUSB, IIO_VOLTAGE, "VUSB"),
|
||||||
|
RN5T618_ADC_CHANNEL(VSYS, IIO_VOLTAGE, "VSYS"),
|
||||||
|
RN5T618_ADC_CHANNEL(VTHM, IIO_VOLTAGE, "VTHM"),
|
||||||
|
RN5T618_ADC_CHANNEL(AIN1, IIO_VOLTAGE, "AIN1"),
|
||||||
|
RN5T618_ADC_CHANNEL(AIN0, IIO_VOLTAGE, "AIN0")
|
||||||
|
};
|
||||||
|
|
||||||
|
static int rn5t618_adc_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
struct iio_dev *iio_dev;
|
||||||
|
struct rn5t618_adc_data *adc;
|
||||||
|
struct rn5t618 *rn5t618 = dev_get_drvdata(pdev->dev.parent);
|
||||||
|
|
||||||
|
iio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*adc));
|
||||||
|
if (!iio_dev) {
|
||||||
|
dev_err(&pdev->dev, "failed allocating iio device\n");
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
adc = iio_priv(iio_dev);
|
||||||
|
adc->dev = &pdev->dev;
|
||||||
|
adc->rn5t618 = rn5t618;
|
||||||
|
|
||||||
|
if (rn5t618->irq_data)
|
||||||
|
adc->irq = regmap_irq_get_virq(rn5t618->irq_data,
|
||||||
|
RN5T618_IRQ_ADC);
|
||||||
|
|
||||||
|
if (adc->irq <= 0) {
|
||||||
|
dev_err(&pdev->dev, "get virq failed\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
init_completion(&adc->conv_completion);
|
||||||
|
|
||||||
|
iio_dev->name = dev_name(&pdev->dev);
|
||||||
|
iio_dev->dev.parent = &pdev->dev;
|
||||||
|
iio_dev->info = &rn5t618_adc_iio_info;
|
||||||
|
iio_dev->modes = INDIO_DIRECT_MODE;
|
||||||
|
iio_dev->channels = rn5t618_adc_iio_channels;
|
||||||
|
iio_dev->num_channels = ARRAY_SIZE(rn5t618_adc_iio_channels);
|
||||||
|
|
||||||
|
/* stop any auto-conversion */
|
||||||
|
ret = regmap_write(rn5t618->regmap, RN5T618_ADCCNT3, 0);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
platform_set_drvdata(pdev, iio_dev);
|
||||||
|
|
||||||
|
ret = devm_request_threaded_irq(adc->dev, adc->irq, NULL,
|
||||||
|
rn5t618_adc_irq,
|
||||||
|
IRQF_ONESHOT, dev_name(adc->dev),
|
||||||
|
adc);
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(adc->dev, "request irq %d failed: %d\n", adc->irq, ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return devm_iio_device_register(adc->dev, iio_dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct platform_driver rn5t618_adc_driver = {
|
||||||
|
.driver = {
|
||||||
|
.name = "rn5t618-adc",
|
||||||
|
},
|
||||||
|
.probe = rn5t618_adc_probe,
|
||||||
|
};
|
||||||
|
|
||||||
|
module_platform_driver(rn5t618_adc_driver);
|
||||||
|
MODULE_ALIAS("platform:rn5t618-adc");
|
||||||
|
MODULE_DESCRIPTION("RICOH RN5T618 ADC driver");
|
||||||
|
MODULE_LICENSE("GPL");
|
|
@ -194,6 +194,16 @@ config GP2AP020A00F
|
||||||
To compile this driver as a module, choose M here: the
|
To compile this driver as a module, choose M here: the
|
||||||
module will be called gp2ap020a00f.
|
module will be called gp2ap020a00f.
|
||||||
|
|
||||||
|
config IQS621_ALS
|
||||||
|
tristate "Azoteq IQS621/622 ambient light sensors"
|
||||||
|
depends on MFD_IQS62X || COMPILE_TEST
|
||||||
|
help
|
||||||
|
Say Y here if you want to build support for the Azoteq IQS621
|
||||||
|
and IQS622 ambient light sensors.
|
||||||
|
|
||||||
|
To compile this driver as a module, choose M here: the module
|
||||||
|
will be called iqs621-als.
|
||||||
|
|
||||||
config SENSORS_ISL29018
|
config SENSORS_ISL29018
|
||||||
tristate "Intersil 29018 light and proximity sensor"
|
tristate "Intersil 29018 light and proximity sensor"
|
||||||
depends on I2C
|
depends on I2C
|
||||||
|
|
|
@ -23,6 +23,7 @@ obj-$(CONFIG_GP2AP002) += gp2ap002.o
|
||||||
obj-$(CONFIG_GP2AP020A00F) += gp2ap020a00f.o
|
obj-$(CONFIG_GP2AP020A00F) += gp2ap020a00f.o
|
||||||
obj-$(CONFIG_HID_SENSOR_ALS) += hid-sensor-als.o
|
obj-$(CONFIG_HID_SENSOR_ALS) += hid-sensor-als.o
|
||||||
obj-$(CONFIG_HID_SENSOR_PROX) += hid-sensor-prox.o
|
obj-$(CONFIG_HID_SENSOR_PROX) += hid-sensor-prox.o
|
||||||
|
obj-$(CONFIG_IQS621_ALS) += iqs621-als.o
|
||||||
obj-$(CONFIG_SENSORS_ISL29018) += isl29018.o
|
obj-$(CONFIG_SENSORS_ISL29018) += isl29018.o
|
||||||
obj-$(CONFIG_SENSORS_ISL29028) += isl29028.o
|
obj-$(CONFIG_SENSORS_ISL29028) += isl29028.o
|
||||||
obj-$(CONFIG_ISL29125) += isl29125.o
|
obj-$(CONFIG_ISL29125) += isl29125.o
|
||||||
|
|
|
@ -0,0 +1,617 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
|
/*
|
||||||
|
* Azoteq IQS621/622 Ambient Light Sensors
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019 Jeff LaBundy <jeff@labundy.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/device.h>
|
||||||
|
#include <linux/iio/events.h>
|
||||||
|
#include <linux/iio/iio.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/mfd/iqs62x.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/mutex.h>
|
||||||
|
#include <linux/notifier.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/regmap.h>
|
||||||
|
|
||||||
|
#define IQS621_ALS_FLAGS_LIGHT BIT(7)
|
||||||
|
#define IQS621_ALS_FLAGS_RANGE GENMASK(3, 0)
|
||||||
|
|
||||||
|
#define IQS621_ALS_UI_OUT 0x17
|
||||||
|
|
||||||
|
#define IQS621_ALS_THRESH_DARK 0x80
|
||||||
|
#define IQS621_ALS_THRESH_LIGHT 0x81
|
||||||
|
|
||||||
|
#define IQS622_IR_RANGE 0x15
|
||||||
|
#define IQS622_IR_FLAGS 0x16
|
||||||
|
#define IQS622_IR_FLAGS_TOUCH BIT(1)
|
||||||
|
#define IQS622_IR_FLAGS_PROX BIT(0)
|
||||||
|
|
||||||
|
#define IQS622_IR_UI_OUT 0x17
|
||||||
|
|
||||||
|
#define IQS622_IR_THRESH_PROX 0x91
|
||||||
|
#define IQS622_IR_THRESH_TOUCH 0x92
|
||||||
|
|
||||||
|
struct iqs621_als_private {
|
||||||
|
struct iqs62x_core *iqs62x;
|
||||||
|
struct notifier_block notifier;
|
||||||
|
struct mutex lock;
|
||||||
|
bool light_en;
|
||||||
|
bool range_en;
|
||||||
|
bool prox_en;
|
||||||
|
u8 als_flags;
|
||||||
|
u8 ir_flags_mask;
|
||||||
|
u8 ir_flags;
|
||||||
|
u8 thresh_light;
|
||||||
|
u8 thresh_dark;
|
||||||
|
u8 thresh_prox;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int iqs621_als_init(struct iqs621_als_private *iqs621_als)
|
||||||
|
{
|
||||||
|
struct iqs62x_core *iqs62x = iqs621_als->iqs62x;
|
||||||
|
unsigned int event_mask = 0;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
switch (iqs621_als->ir_flags_mask) {
|
||||||
|
case IQS622_IR_FLAGS_TOUCH:
|
||||||
|
ret = regmap_write(iqs62x->regmap, IQS622_IR_THRESH_TOUCH,
|
||||||
|
iqs621_als->thresh_prox);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IQS622_IR_FLAGS_PROX:
|
||||||
|
ret = regmap_write(iqs62x->regmap, IQS622_IR_THRESH_PROX,
|
||||||
|
iqs621_als->thresh_prox);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
ret = regmap_write(iqs62x->regmap, IQS621_ALS_THRESH_LIGHT,
|
||||||
|
iqs621_als->thresh_light);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = regmap_write(iqs62x->regmap, IQS621_ALS_THRESH_DARK,
|
||||||
|
iqs621_als->thresh_dark);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (iqs621_als->light_en || iqs621_als->range_en)
|
||||||
|
event_mask |= iqs62x->dev_desc->als_mask;
|
||||||
|
|
||||||
|
if (iqs621_als->prox_en)
|
||||||
|
event_mask |= iqs62x->dev_desc->ir_mask;
|
||||||
|
|
||||||
|
return regmap_update_bits(iqs62x->regmap, IQS620_GLBL_EVENT_MASK,
|
||||||
|
event_mask, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int iqs621_als_notifier(struct notifier_block *notifier,
|
||||||
|
unsigned long event_flags, void *context)
|
||||||
|
{
|
||||||
|
struct iqs62x_event_data *event_data = context;
|
||||||
|
struct iqs621_als_private *iqs621_als;
|
||||||
|
struct iio_dev *indio_dev;
|
||||||
|
bool light_new, light_old;
|
||||||
|
bool prox_new, prox_old;
|
||||||
|
u8 range_new, range_old;
|
||||||
|
s64 timestamp;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
iqs621_als = container_of(notifier, struct iqs621_als_private,
|
||||||
|
notifier);
|
||||||
|
indio_dev = iio_priv_to_dev(iqs621_als);
|
||||||
|
timestamp = iio_get_time_ns(indio_dev);
|
||||||
|
|
||||||
|
mutex_lock(&iqs621_als->lock);
|
||||||
|
|
||||||
|
if (event_flags & BIT(IQS62X_EVENT_SYS_RESET)) {
|
||||||
|
ret = iqs621_als_init(iqs621_als);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(indio_dev->dev.parent,
|
||||||
|
"Failed to re-initialize device: %d\n", ret);
|
||||||
|
ret = NOTIFY_BAD;
|
||||||
|
} else {
|
||||||
|
ret = NOTIFY_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
goto err_mutex;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!iqs621_als->light_en && !iqs621_als->range_en &&
|
||||||
|
!iqs621_als->prox_en) {
|
||||||
|
ret = NOTIFY_DONE;
|
||||||
|
goto err_mutex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* IQS621 only */
|
||||||
|
light_new = event_data->als_flags & IQS621_ALS_FLAGS_LIGHT;
|
||||||
|
light_old = iqs621_als->als_flags & IQS621_ALS_FLAGS_LIGHT;
|
||||||
|
|
||||||
|
if (iqs621_als->light_en && light_new && !light_old)
|
||||||
|
iio_push_event(indio_dev,
|
||||||
|
IIO_UNMOD_EVENT_CODE(IIO_LIGHT, 0,
|
||||||
|
IIO_EV_TYPE_THRESH,
|
||||||
|
IIO_EV_DIR_RISING),
|
||||||
|
timestamp);
|
||||||
|
else if (iqs621_als->light_en && !light_new && light_old)
|
||||||
|
iio_push_event(indio_dev,
|
||||||
|
IIO_UNMOD_EVENT_CODE(IIO_LIGHT, 0,
|
||||||
|
IIO_EV_TYPE_THRESH,
|
||||||
|
IIO_EV_DIR_FALLING),
|
||||||
|
timestamp);
|
||||||
|
|
||||||
|
/* IQS621 and IQS622 */
|
||||||
|
range_new = event_data->als_flags & IQS621_ALS_FLAGS_RANGE;
|
||||||
|
range_old = iqs621_als->als_flags & IQS621_ALS_FLAGS_RANGE;
|
||||||
|
|
||||||
|
if (iqs621_als->range_en && (range_new > range_old))
|
||||||
|
iio_push_event(indio_dev,
|
||||||
|
IIO_UNMOD_EVENT_CODE(IIO_INTENSITY, 0,
|
||||||
|
IIO_EV_TYPE_CHANGE,
|
||||||
|
IIO_EV_DIR_RISING),
|
||||||
|
timestamp);
|
||||||
|
else if (iqs621_als->range_en && (range_new < range_old))
|
||||||
|
iio_push_event(indio_dev,
|
||||||
|
IIO_UNMOD_EVENT_CODE(IIO_INTENSITY, 0,
|
||||||
|
IIO_EV_TYPE_CHANGE,
|
||||||
|
IIO_EV_DIR_FALLING),
|
||||||
|
timestamp);
|
||||||
|
|
||||||
|
/* IQS622 only */
|
||||||
|
prox_new = event_data->ir_flags & iqs621_als->ir_flags_mask;
|
||||||
|
prox_old = iqs621_als->ir_flags & iqs621_als->ir_flags_mask;
|
||||||
|
|
||||||
|
if (iqs621_als->prox_en && prox_new && !prox_old)
|
||||||
|
iio_push_event(indio_dev,
|
||||||
|
IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 0,
|
||||||
|
IIO_EV_TYPE_THRESH,
|
||||||
|
IIO_EV_DIR_RISING),
|
||||||
|
timestamp);
|
||||||
|
else if (iqs621_als->prox_en && !prox_new && prox_old)
|
||||||
|
iio_push_event(indio_dev,
|
||||||
|
IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 0,
|
||||||
|
IIO_EV_TYPE_THRESH,
|
||||||
|
IIO_EV_DIR_FALLING),
|
||||||
|
timestamp);
|
||||||
|
|
||||||
|
iqs621_als->als_flags = event_data->als_flags;
|
||||||
|
iqs621_als->ir_flags = event_data->ir_flags;
|
||||||
|
ret = NOTIFY_OK;
|
||||||
|
|
||||||
|
err_mutex:
|
||||||
|
mutex_unlock(&iqs621_als->lock);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void iqs621_als_notifier_unregister(void *context)
|
||||||
|
{
|
||||||
|
struct iqs621_als_private *iqs621_als = context;
|
||||||
|
struct iio_dev *indio_dev = iio_priv_to_dev(iqs621_als);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = blocking_notifier_chain_unregister(&iqs621_als->iqs62x->nh,
|
||||||
|
&iqs621_als->notifier);
|
||||||
|
if (ret)
|
||||||
|
dev_err(indio_dev->dev.parent,
|
||||||
|
"Failed to unregister notifier: %d\n", ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int iqs621_als_read_raw(struct iio_dev *indio_dev,
|
||||||
|
struct iio_chan_spec const *chan,
|
||||||
|
int *val, int *val2, long mask)
|
||||||
|
{
|
||||||
|
struct iqs621_als_private *iqs621_als = iio_priv(indio_dev);
|
||||||
|
struct iqs62x_core *iqs62x = iqs621_als->iqs62x;
|
||||||
|
int ret;
|
||||||
|
__le16 val_buf;
|
||||||
|
|
||||||
|
switch (chan->type) {
|
||||||
|
case IIO_INTENSITY:
|
||||||
|
ret = regmap_read(iqs62x->regmap, chan->address, val);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
*val &= IQS621_ALS_FLAGS_RANGE;
|
||||||
|
return IIO_VAL_INT;
|
||||||
|
|
||||||
|
case IIO_PROXIMITY:
|
||||||
|
case IIO_LIGHT:
|
||||||
|
ret = regmap_raw_read(iqs62x->regmap, chan->address, &val_buf,
|
||||||
|
sizeof(val_buf));
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
*val = le16_to_cpu(val_buf);
|
||||||
|
return IIO_VAL_INT;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int iqs621_als_read_event_config(struct iio_dev *indio_dev,
|
||||||
|
const struct iio_chan_spec *chan,
|
||||||
|
enum iio_event_type type,
|
||||||
|
enum iio_event_direction dir)
|
||||||
|
{
|
||||||
|
struct iqs621_als_private *iqs621_als = iio_priv(indio_dev);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
mutex_lock(&iqs621_als->lock);
|
||||||
|
|
||||||
|
switch (chan->type) {
|
||||||
|
case IIO_LIGHT:
|
||||||
|
ret = iqs621_als->light_en;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IIO_INTENSITY:
|
||||||
|
ret = iqs621_als->range_en;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IIO_PROXIMITY:
|
||||||
|
ret = iqs621_als->prox_en;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
ret = -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_unlock(&iqs621_als->lock);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int iqs621_als_write_event_config(struct iio_dev *indio_dev,
|
||||||
|
const struct iio_chan_spec *chan,
|
||||||
|
enum iio_event_type type,
|
||||||
|
enum iio_event_direction dir,
|
||||||
|
int state)
|
||||||
|
{
|
||||||
|
struct iqs621_als_private *iqs621_als = iio_priv(indio_dev);
|
||||||
|
struct iqs62x_core *iqs62x = iqs621_als->iqs62x;
|
||||||
|
unsigned int val;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
mutex_lock(&iqs621_als->lock);
|
||||||
|
|
||||||
|
ret = regmap_read(iqs62x->regmap, iqs62x->dev_desc->als_flags, &val);
|
||||||
|
if (ret)
|
||||||
|
goto err_mutex;
|
||||||
|
iqs621_als->als_flags = val;
|
||||||
|
|
||||||
|
switch (chan->type) {
|
||||||
|
case IIO_LIGHT:
|
||||||
|
ret = regmap_update_bits(iqs62x->regmap, IQS620_GLBL_EVENT_MASK,
|
||||||
|
iqs62x->dev_desc->als_mask,
|
||||||
|
iqs621_als->range_en || state ? 0 :
|
||||||
|
0xFF);
|
||||||
|
if (!ret)
|
||||||
|
iqs621_als->light_en = state;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IIO_INTENSITY:
|
||||||
|
ret = regmap_update_bits(iqs62x->regmap, IQS620_GLBL_EVENT_MASK,
|
||||||
|
iqs62x->dev_desc->als_mask,
|
||||||
|
iqs621_als->light_en || state ? 0 :
|
||||||
|
0xFF);
|
||||||
|
if (!ret)
|
||||||
|
iqs621_als->range_en = state;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IIO_PROXIMITY:
|
||||||
|
ret = regmap_read(iqs62x->regmap, IQS622_IR_FLAGS, &val);
|
||||||
|
if (ret)
|
||||||
|
goto err_mutex;
|
||||||
|
iqs621_als->ir_flags = val;
|
||||||
|
|
||||||
|
ret = regmap_update_bits(iqs62x->regmap, IQS620_GLBL_EVENT_MASK,
|
||||||
|
iqs62x->dev_desc->ir_mask,
|
||||||
|
state ? 0 : 0xFF);
|
||||||
|
if (!ret)
|
||||||
|
iqs621_als->prox_en = state;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
ret = -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
err_mutex:
|
||||||
|
mutex_unlock(&iqs621_als->lock);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int iqs621_als_read_event_value(struct iio_dev *indio_dev,
|
||||||
|
const struct iio_chan_spec *chan,
|
||||||
|
enum iio_event_type type,
|
||||||
|
enum iio_event_direction dir,
|
||||||
|
enum iio_event_info info,
|
||||||
|
int *val, int *val2)
|
||||||
|
{
|
||||||
|
struct iqs621_als_private *iqs621_als = iio_priv(indio_dev);
|
||||||
|
int ret = IIO_VAL_INT;
|
||||||
|
|
||||||
|
mutex_lock(&iqs621_als->lock);
|
||||||
|
|
||||||
|
switch (dir) {
|
||||||
|
case IIO_EV_DIR_RISING:
|
||||||
|
*val = iqs621_als->thresh_light * 16;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IIO_EV_DIR_FALLING:
|
||||||
|
*val = iqs621_als->thresh_dark * 4;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IIO_EV_DIR_EITHER:
|
||||||
|
if (iqs621_als->ir_flags_mask == IQS622_IR_FLAGS_TOUCH)
|
||||||
|
*val = iqs621_als->thresh_prox * 4;
|
||||||
|
else
|
||||||
|
*val = iqs621_als->thresh_prox;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
ret = -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_unlock(&iqs621_als->lock);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int iqs621_als_write_event_value(struct iio_dev *indio_dev,
|
||||||
|
const struct iio_chan_spec *chan,
|
||||||
|
enum iio_event_type type,
|
||||||
|
enum iio_event_direction dir,
|
||||||
|
enum iio_event_info info,
|
||||||
|
int val, int val2)
|
||||||
|
{
|
||||||
|
struct iqs621_als_private *iqs621_als = iio_priv(indio_dev);
|
||||||
|
struct iqs62x_core *iqs62x = iqs621_als->iqs62x;
|
||||||
|
unsigned int thresh_reg, thresh_val;
|
||||||
|
u8 ir_flags_mask, *thresh_cache;
|
||||||
|
int ret = -EINVAL;
|
||||||
|
|
||||||
|
mutex_lock(&iqs621_als->lock);
|
||||||
|
|
||||||
|
switch (dir) {
|
||||||
|
case IIO_EV_DIR_RISING:
|
||||||
|
thresh_reg = IQS621_ALS_THRESH_LIGHT;
|
||||||
|
thresh_val = val / 16;
|
||||||
|
|
||||||
|
thresh_cache = &iqs621_als->thresh_light;
|
||||||
|
ir_flags_mask = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IIO_EV_DIR_FALLING:
|
||||||
|
thresh_reg = IQS621_ALS_THRESH_DARK;
|
||||||
|
thresh_val = val / 4;
|
||||||
|
|
||||||
|
thresh_cache = &iqs621_als->thresh_dark;
|
||||||
|
ir_flags_mask = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IIO_EV_DIR_EITHER:
|
||||||
|
/*
|
||||||
|
* The IQS622 supports two detection thresholds, both measured
|
||||||
|
* in the same arbitrary units reported by read_raw: proximity
|
||||||
|
* (0 through 255 in steps of 1), and touch (0 through 1020 in
|
||||||
|
* steps of 4).
|
||||||
|
*
|
||||||
|
* Based on the single detection threshold chosen by the user,
|
||||||
|
* select the hardware threshold that gives the best trade-off
|
||||||
|
* between range and resolution.
|
||||||
|
*
|
||||||
|
* By default, the close-range (but coarse) touch threshold is
|
||||||
|
* chosen during probe.
|
||||||
|
*/
|
||||||
|
switch (val) {
|
||||||
|
case 0 ... 255:
|
||||||
|
thresh_reg = IQS622_IR_THRESH_PROX;
|
||||||
|
thresh_val = val;
|
||||||
|
|
||||||
|
ir_flags_mask = IQS622_IR_FLAGS_PROX;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 256 ... 1020:
|
||||||
|
thresh_reg = IQS622_IR_THRESH_TOUCH;
|
||||||
|
thresh_val = val / 4;
|
||||||
|
|
||||||
|
ir_flags_mask = IQS622_IR_FLAGS_TOUCH;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
goto err_mutex;
|
||||||
|
}
|
||||||
|
|
||||||
|
thresh_cache = &iqs621_als->thresh_prox;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
goto err_mutex;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (thresh_val > 0xFF)
|
||||||
|
goto err_mutex;
|
||||||
|
|
||||||
|
ret = regmap_write(iqs62x->regmap, thresh_reg, thresh_val);
|
||||||
|
if (ret)
|
||||||
|
goto err_mutex;
|
||||||
|
|
||||||
|
*thresh_cache = thresh_val;
|
||||||
|
iqs621_als->ir_flags_mask = ir_flags_mask;
|
||||||
|
|
||||||
|
err_mutex:
|
||||||
|
mutex_unlock(&iqs621_als->lock);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct iio_info iqs621_als_info = {
|
||||||
|
.read_raw = &iqs621_als_read_raw,
|
||||||
|
.read_event_config = iqs621_als_read_event_config,
|
||||||
|
.write_event_config = iqs621_als_write_event_config,
|
||||||
|
.read_event_value = iqs621_als_read_event_value,
|
||||||
|
.write_event_value = iqs621_als_write_event_value,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct iio_event_spec iqs621_als_range_events[] = {
|
||||||
|
{
|
||||||
|
.type = IIO_EV_TYPE_CHANGE,
|
||||||
|
.dir = IIO_EV_DIR_EITHER,
|
||||||
|
.mask_separate = BIT(IIO_EV_INFO_ENABLE),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct iio_event_spec iqs621_als_light_events[] = {
|
||||||
|
{
|
||||||
|
.type = IIO_EV_TYPE_THRESH,
|
||||||
|
.dir = IIO_EV_DIR_EITHER,
|
||||||
|
.mask_separate = BIT(IIO_EV_INFO_ENABLE),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.type = IIO_EV_TYPE_THRESH,
|
||||||
|
.dir = IIO_EV_DIR_RISING,
|
||||||
|
.mask_separate = BIT(IIO_EV_INFO_VALUE),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.type = IIO_EV_TYPE_THRESH,
|
||||||
|
.dir = IIO_EV_DIR_FALLING,
|
||||||
|
.mask_separate = BIT(IIO_EV_INFO_VALUE),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct iio_chan_spec iqs621_als_channels[] = {
|
||||||
|
{
|
||||||
|
.type = IIO_INTENSITY,
|
||||||
|
.address = IQS621_ALS_FLAGS,
|
||||||
|
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
|
||||||
|
.event_spec = iqs621_als_range_events,
|
||||||
|
.num_event_specs = ARRAY_SIZE(iqs621_als_range_events),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.type = IIO_LIGHT,
|
||||||
|
.address = IQS621_ALS_UI_OUT,
|
||||||
|
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
|
||||||
|
.event_spec = iqs621_als_light_events,
|
||||||
|
.num_event_specs = ARRAY_SIZE(iqs621_als_light_events),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct iio_event_spec iqs622_als_prox_events[] = {
|
||||||
|
{
|
||||||
|
.type = IIO_EV_TYPE_THRESH,
|
||||||
|
.dir = IIO_EV_DIR_EITHER,
|
||||||
|
.mask_separate = BIT(IIO_EV_INFO_ENABLE) |
|
||||||
|
BIT(IIO_EV_INFO_VALUE),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct iio_chan_spec iqs622_als_channels[] = {
|
||||||
|
{
|
||||||
|
.type = IIO_INTENSITY,
|
||||||
|
.channel2 = IIO_MOD_LIGHT_BOTH,
|
||||||
|
.address = IQS622_ALS_FLAGS,
|
||||||
|
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
|
||||||
|
.event_spec = iqs621_als_range_events,
|
||||||
|
.num_event_specs = ARRAY_SIZE(iqs621_als_range_events),
|
||||||
|
.modified = true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.type = IIO_INTENSITY,
|
||||||
|
.channel2 = IIO_MOD_LIGHT_IR,
|
||||||
|
.address = IQS622_IR_RANGE,
|
||||||
|
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
|
||||||
|
.modified = true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.type = IIO_PROXIMITY,
|
||||||
|
.address = IQS622_IR_UI_OUT,
|
||||||
|
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
|
||||||
|
.event_spec = iqs622_als_prox_events,
|
||||||
|
.num_event_specs = ARRAY_SIZE(iqs622_als_prox_events),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static int iqs621_als_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct iqs62x_core *iqs62x = dev_get_drvdata(pdev->dev.parent);
|
||||||
|
struct iqs621_als_private *iqs621_als;
|
||||||
|
struct iio_dev *indio_dev;
|
||||||
|
unsigned int val;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*iqs621_als));
|
||||||
|
if (!indio_dev)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
iqs621_als = iio_priv(indio_dev);
|
||||||
|
iqs621_als->iqs62x = iqs62x;
|
||||||
|
|
||||||
|
if (iqs62x->dev_desc->prod_num == IQS622_PROD_NUM) {
|
||||||
|
ret = regmap_read(iqs62x->regmap, IQS622_IR_THRESH_TOUCH,
|
||||||
|
&val);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
iqs621_als->thresh_prox = val;
|
||||||
|
iqs621_als->ir_flags_mask = IQS622_IR_FLAGS_TOUCH;
|
||||||
|
|
||||||
|
indio_dev->channels = iqs622_als_channels;
|
||||||
|
indio_dev->num_channels = ARRAY_SIZE(iqs622_als_channels);
|
||||||
|
} else {
|
||||||
|
ret = regmap_read(iqs62x->regmap, IQS621_ALS_THRESH_LIGHT,
|
||||||
|
&val);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
iqs621_als->thresh_light = val;
|
||||||
|
|
||||||
|
ret = regmap_read(iqs62x->regmap, IQS621_ALS_THRESH_DARK,
|
||||||
|
&val);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
iqs621_als->thresh_dark = val;
|
||||||
|
|
||||||
|
indio_dev->channels = iqs621_als_channels;
|
||||||
|
indio_dev->num_channels = ARRAY_SIZE(iqs621_als_channels);
|
||||||
|
}
|
||||||
|
|
||||||
|
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||||
|
indio_dev->dev.parent = &pdev->dev;
|
||||||
|
indio_dev->name = iqs62x->dev_desc->dev_name;
|
||||||
|
indio_dev->info = &iqs621_als_info;
|
||||||
|
|
||||||
|
mutex_init(&iqs621_als->lock);
|
||||||
|
|
||||||
|
iqs621_als->notifier.notifier_call = iqs621_als_notifier;
|
||||||
|
ret = blocking_notifier_chain_register(&iqs621_als->iqs62x->nh,
|
||||||
|
&iqs621_als->notifier);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(&pdev->dev, "Failed to register notifier: %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = devm_add_action_or_reset(&pdev->dev,
|
||||||
|
iqs621_als_notifier_unregister,
|
||||||
|
iqs621_als);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return devm_iio_device_register(&pdev->dev, indio_dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct platform_driver iqs621_als_platform_driver = {
|
||||||
|
.driver = {
|
||||||
|
.name = "iqs621-als",
|
||||||
|
},
|
||||||
|
.probe = iqs621_als_probe,
|
||||||
|
};
|
||||||
|
module_platform_driver(iqs621_als_platform_driver);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Jeff LaBundy <jeff@labundy.com>");
|
||||||
|
MODULE_DESCRIPTION("Azoteq IQS621/622 Ambient Light Sensors");
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
MODULE_ALIAS("platform:iqs621-als");
|
|
@ -0,0 +1,19 @@
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
#
|
||||||
|
# Linear and angular position sensors
|
||||||
|
#
|
||||||
|
# When adding new entries keep the list in alphabetical order
|
||||||
|
|
||||||
|
menu "Linear and angular position sensors"
|
||||||
|
|
||||||
|
config IQS624_POS
|
||||||
|
tristate "Azoteq IQS624/625 angular position sensors"
|
||||||
|
depends on MFD_IQS62X || COMPILE_TEST
|
||||||
|
help
|
||||||
|
Say Y here if you want to build support for the Azoteq IQS624
|
||||||
|
and IQS625 angular position sensors.
|
||||||
|
|
||||||
|
To compile this driver as a module, choose M here: the module
|
||||||
|
will be called iqs624-pos.
|
||||||
|
|
||||||
|
endmenu
|
|
@ -0,0 +1,7 @@
|
||||||
|
#
|
||||||
|
# Makefile for IIO linear and angular position sensors
|
||||||
|
#
|
||||||
|
|
||||||
|
# When adding new entries keep the list in alphabetical order
|
||||||
|
|
||||||
|
obj-$(CONFIG_IQS624_POS) += iqs624-pos.o
|
|
@ -0,0 +1,284 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
|
/*
|
||||||
|
* Azoteq IQS624/625 Angular Position Sensors
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019 Jeff LaBundy <jeff@labundy.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/device.h>
|
||||||
|
#include <linux/iio/events.h>
|
||||||
|
#include <linux/iio/iio.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/mfd/iqs62x.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/mutex.h>
|
||||||
|
#include <linux/notifier.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/regmap.h>
|
||||||
|
|
||||||
|
#define IQS624_POS_DEG_OUT 0x16
|
||||||
|
|
||||||
|
#define IQS624_POS_SCALE1 (314159 / 180)
|
||||||
|
#define IQS624_POS_SCALE2 100000
|
||||||
|
|
||||||
|
struct iqs624_pos_private {
|
||||||
|
struct iqs62x_core *iqs62x;
|
||||||
|
struct notifier_block notifier;
|
||||||
|
struct mutex lock;
|
||||||
|
bool angle_en;
|
||||||
|
u16 angle;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int iqs624_pos_angle_en(struct iqs62x_core *iqs62x, bool angle_en)
|
||||||
|
{
|
||||||
|
unsigned int event_mask = IQS624_HALL_UI_WHL_EVENT;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The IQS625 reports angular position in the form of coarse intervals,
|
||||||
|
* so only interval change events are unmasked. Conversely, the IQS624
|
||||||
|
* reports angular position down to one degree of resolution, so wheel
|
||||||
|
* movement events are unmasked instead.
|
||||||
|
*/
|
||||||
|
if (iqs62x->dev_desc->prod_num == IQS625_PROD_NUM)
|
||||||
|
event_mask = IQS624_HALL_UI_INT_EVENT;
|
||||||
|
|
||||||
|
return regmap_update_bits(iqs62x->regmap, IQS624_HALL_UI, event_mask,
|
||||||
|
angle_en ? 0 : 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int iqs624_pos_notifier(struct notifier_block *notifier,
|
||||||
|
unsigned long event_flags, void *context)
|
||||||
|
{
|
||||||
|
struct iqs62x_event_data *event_data = context;
|
||||||
|
struct iqs624_pos_private *iqs624_pos;
|
||||||
|
struct iqs62x_core *iqs62x;
|
||||||
|
struct iio_dev *indio_dev;
|
||||||
|
u16 angle = event_data->ui_data;
|
||||||
|
s64 timestamp;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
iqs624_pos = container_of(notifier, struct iqs624_pos_private,
|
||||||
|
notifier);
|
||||||
|
indio_dev = iio_priv_to_dev(iqs624_pos);
|
||||||
|
timestamp = iio_get_time_ns(indio_dev);
|
||||||
|
|
||||||
|
iqs62x = iqs624_pos->iqs62x;
|
||||||
|
if (iqs62x->dev_desc->prod_num == IQS625_PROD_NUM)
|
||||||
|
angle = event_data->interval;
|
||||||
|
|
||||||
|
mutex_lock(&iqs624_pos->lock);
|
||||||
|
|
||||||
|
if (event_flags & BIT(IQS62X_EVENT_SYS_RESET)) {
|
||||||
|
ret = iqs624_pos_angle_en(iqs62x, iqs624_pos->angle_en);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(indio_dev->dev.parent,
|
||||||
|
"Failed to re-initialize device: %d\n", ret);
|
||||||
|
ret = NOTIFY_BAD;
|
||||||
|
} else {
|
||||||
|
ret = NOTIFY_OK;
|
||||||
|
}
|
||||||
|
} else if (iqs624_pos->angle_en && (angle != iqs624_pos->angle)) {
|
||||||
|
iio_push_event(indio_dev,
|
||||||
|
IIO_UNMOD_EVENT_CODE(IIO_ANGL, 0,
|
||||||
|
IIO_EV_TYPE_CHANGE,
|
||||||
|
IIO_EV_DIR_NONE),
|
||||||
|
timestamp);
|
||||||
|
|
||||||
|
iqs624_pos->angle = angle;
|
||||||
|
ret = NOTIFY_OK;
|
||||||
|
} else {
|
||||||
|
ret = NOTIFY_DONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_unlock(&iqs624_pos->lock);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void iqs624_pos_notifier_unregister(void *context)
|
||||||
|
{
|
||||||
|
struct iqs624_pos_private *iqs624_pos = context;
|
||||||
|
struct iio_dev *indio_dev = iio_priv_to_dev(iqs624_pos);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = blocking_notifier_chain_unregister(&iqs624_pos->iqs62x->nh,
|
||||||
|
&iqs624_pos->notifier);
|
||||||
|
if (ret)
|
||||||
|
dev_err(indio_dev->dev.parent,
|
||||||
|
"Failed to unregister notifier: %d\n", ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int iqs624_pos_angle_get(struct iqs62x_core *iqs62x, unsigned int *val)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
__le16 val_buf;
|
||||||
|
|
||||||
|
if (iqs62x->dev_desc->prod_num == IQS625_PROD_NUM)
|
||||||
|
return regmap_read(iqs62x->regmap, iqs62x->dev_desc->interval,
|
||||||
|
val);
|
||||||
|
|
||||||
|
ret = regmap_raw_read(iqs62x->regmap, IQS624_POS_DEG_OUT, &val_buf,
|
||||||
|
sizeof(val_buf));
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
*val = le16_to_cpu(val_buf);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int iqs624_pos_read_raw(struct iio_dev *indio_dev,
|
||||||
|
struct iio_chan_spec const *chan,
|
||||||
|
int *val, int *val2, long mask)
|
||||||
|
{
|
||||||
|
struct iqs624_pos_private *iqs624_pos = iio_priv(indio_dev);
|
||||||
|
struct iqs62x_core *iqs62x = iqs624_pos->iqs62x;
|
||||||
|
unsigned int scale = 1;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
switch (mask) {
|
||||||
|
case IIO_CHAN_INFO_RAW:
|
||||||
|
ret = iqs624_pos_angle_get(iqs62x, val);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return IIO_VAL_INT;
|
||||||
|
|
||||||
|
case IIO_CHAN_INFO_SCALE:
|
||||||
|
if (iqs62x->dev_desc->prod_num == IQS625_PROD_NUM) {
|
||||||
|
ret = regmap_read(iqs62x->regmap, IQS624_INTERVAL_DIV,
|
||||||
|
&scale);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
*val = scale * IQS624_POS_SCALE1;
|
||||||
|
*val2 = IQS624_POS_SCALE2;
|
||||||
|
return IIO_VAL_FRACTIONAL;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int iqs624_pos_read_event_config(struct iio_dev *indio_dev,
|
||||||
|
const struct iio_chan_spec *chan,
|
||||||
|
enum iio_event_type type,
|
||||||
|
enum iio_event_direction dir)
|
||||||
|
{
|
||||||
|
struct iqs624_pos_private *iqs624_pos = iio_priv(indio_dev);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
mutex_lock(&iqs624_pos->lock);
|
||||||
|
ret = iqs624_pos->angle_en;
|
||||||
|
mutex_unlock(&iqs624_pos->lock);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int iqs624_pos_write_event_config(struct iio_dev *indio_dev,
|
||||||
|
const struct iio_chan_spec *chan,
|
||||||
|
enum iio_event_type type,
|
||||||
|
enum iio_event_direction dir,
|
||||||
|
int state)
|
||||||
|
{
|
||||||
|
struct iqs624_pos_private *iqs624_pos = iio_priv(indio_dev);
|
||||||
|
struct iqs62x_core *iqs62x = iqs624_pos->iqs62x;
|
||||||
|
unsigned int val;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
mutex_lock(&iqs624_pos->lock);
|
||||||
|
|
||||||
|
ret = iqs624_pos_angle_get(iqs62x, &val);
|
||||||
|
if (ret)
|
||||||
|
goto err_mutex;
|
||||||
|
|
||||||
|
ret = iqs624_pos_angle_en(iqs62x, state);
|
||||||
|
if (ret)
|
||||||
|
goto err_mutex;
|
||||||
|
|
||||||
|
iqs624_pos->angle = val;
|
||||||
|
iqs624_pos->angle_en = state;
|
||||||
|
|
||||||
|
err_mutex:
|
||||||
|
mutex_unlock(&iqs624_pos->lock);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct iio_info iqs624_pos_info = {
|
||||||
|
.read_raw = &iqs624_pos_read_raw,
|
||||||
|
.read_event_config = iqs624_pos_read_event_config,
|
||||||
|
.write_event_config = iqs624_pos_write_event_config,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct iio_event_spec iqs624_pos_events[] = {
|
||||||
|
{
|
||||||
|
.type = IIO_EV_TYPE_CHANGE,
|
||||||
|
.dir = IIO_EV_DIR_NONE,
|
||||||
|
.mask_separate = BIT(IIO_EV_INFO_ENABLE),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct iio_chan_spec iqs624_pos_channels[] = {
|
||||||
|
{
|
||||||
|
.type = IIO_ANGL,
|
||||||
|
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
|
||||||
|
BIT(IIO_CHAN_INFO_SCALE),
|
||||||
|
.event_spec = iqs624_pos_events,
|
||||||
|
.num_event_specs = ARRAY_SIZE(iqs624_pos_events),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static int iqs624_pos_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct iqs62x_core *iqs62x = dev_get_drvdata(pdev->dev.parent);
|
||||||
|
struct iqs624_pos_private *iqs624_pos;
|
||||||
|
struct iio_dev *indio_dev;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*iqs624_pos));
|
||||||
|
if (!indio_dev)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
iqs624_pos = iio_priv(indio_dev);
|
||||||
|
iqs624_pos->iqs62x = iqs62x;
|
||||||
|
|
||||||
|
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||||
|
indio_dev->dev.parent = &pdev->dev;
|
||||||
|
indio_dev->channels = iqs624_pos_channels;
|
||||||
|
indio_dev->num_channels = ARRAY_SIZE(iqs624_pos_channels);
|
||||||
|
indio_dev->name = iqs62x->dev_desc->dev_name;
|
||||||
|
indio_dev->info = &iqs624_pos_info;
|
||||||
|
|
||||||
|
mutex_init(&iqs624_pos->lock);
|
||||||
|
|
||||||
|
iqs624_pos->notifier.notifier_call = iqs624_pos_notifier;
|
||||||
|
ret = blocking_notifier_chain_register(&iqs624_pos->iqs62x->nh,
|
||||||
|
&iqs624_pos->notifier);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(&pdev->dev, "Failed to register notifier: %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = devm_add_action_or_reset(&pdev->dev,
|
||||||
|
iqs624_pos_notifier_unregister,
|
||||||
|
iqs624_pos);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return devm_iio_device_register(&pdev->dev, indio_dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct platform_driver iqs624_pos_platform_driver = {
|
||||||
|
.driver = {
|
||||||
|
.name = "iqs624-pos",
|
||||||
|
},
|
||||||
|
.probe = iqs624_pos_probe,
|
||||||
|
};
|
||||||
|
module_platform_driver(iqs624_pos_platform_driver);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Jeff LaBundy <jeff@labundy.com>");
|
||||||
|
MODULE_DESCRIPTION("Azoteq IQS624/625 Angular Position Sensors");
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
MODULE_ALIAS("platform:iqs624-pos");
|
|
@ -4,6 +4,16 @@
|
||||||
#
|
#
|
||||||
menu "Temperature sensors"
|
menu "Temperature sensors"
|
||||||
|
|
||||||
|
config IQS620AT_TEMP
|
||||||
|
tristate "Azoteq IQS620AT temperature sensor"
|
||||||
|
depends on MFD_IQS62X || COMPILE_TEST
|
||||||
|
help
|
||||||
|
Say Y here if you want to build support for the Azoteq IQS620AT
|
||||||
|
temperature sensor.
|
||||||
|
|
||||||
|
To compile this driver as a module, choose M here: the module
|
||||||
|
will be called iqs620at-temp.
|
||||||
|
|
||||||
config LTC2983
|
config LTC2983
|
||||||
tristate "Analog Devices Multi-Sensor Digital Temperature Measurement System"
|
tristate "Analog Devices Multi-Sensor Digital Temperature Measurement System"
|
||||||
depends on SPI
|
depends on SPI
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
# Makefile for industrial I/O temperature drivers
|
# Makefile for industrial I/O temperature drivers
|
||||||
#
|
#
|
||||||
|
|
||||||
|
obj-$(CONFIG_IQS620AT_TEMP) += iqs620at-temp.o
|
||||||
obj-$(CONFIG_LTC2983) += ltc2983.o
|
obj-$(CONFIG_LTC2983) += ltc2983.o
|
||||||
obj-$(CONFIG_HID_SENSOR_TEMP) += hid-sensor-temperature.o
|
obj-$(CONFIG_HID_SENSOR_TEMP) += hid-sensor-temperature.o
|
||||||
obj-$(CONFIG_MAXIM_THERMOCOUPLE) += maxim_thermocouple.o
|
obj-$(CONFIG_MAXIM_THERMOCOUPLE) += maxim_thermocouple.o
|
||||||
|
|
|
@ -0,0 +1,97 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
|
/*
|
||||||
|
* Azoteq IQS620AT Temperature Sensor
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019 Jeff LaBundy <jeff@labundy.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/device.h>
|
||||||
|
#include <linux/iio/iio.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/mfd/iqs62x.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/regmap.h>
|
||||||
|
|
||||||
|
#define IQS620_TEMP_UI_OUT 0x1A
|
||||||
|
|
||||||
|
#define IQS620_TEMP_SCALE 1000
|
||||||
|
#define IQS620_TEMP_OFFSET (-100)
|
||||||
|
|
||||||
|
static int iqs620_temp_read_raw(struct iio_dev *indio_dev,
|
||||||
|
struct iio_chan_spec const *chan,
|
||||||
|
int *val, int *val2, long mask)
|
||||||
|
{
|
||||||
|
struct iqs62x_core *iqs62x = iio_device_get_drvdata(indio_dev);
|
||||||
|
int ret;
|
||||||
|
__le16 val_buf;
|
||||||
|
|
||||||
|
switch (mask) {
|
||||||
|
case IIO_CHAN_INFO_RAW:
|
||||||
|
ret = regmap_raw_read(iqs62x->regmap, IQS620_TEMP_UI_OUT,
|
||||||
|
&val_buf, sizeof(val_buf));
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
*val = le16_to_cpu(val_buf);
|
||||||
|
return IIO_VAL_INT;
|
||||||
|
|
||||||
|
case IIO_CHAN_INFO_SCALE:
|
||||||
|
*val = IQS620_TEMP_SCALE;
|
||||||
|
return IIO_VAL_INT;
|
||||||
|
|
||||||
|
case IIO_CHAN_INFO_OFFSET:
|
||||||
|
*val = IQS620_TEMP_OFFSET;
|
||||||
|
return IIO_VAL_INT;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct iio_info iqs620_temp_info = {
|
||||||
|
.read_raw = &iqs620_temp_read_raw,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct iio_chan_spec iqs620_temp_channels[] = {
|
||||||
|
{
|
||||||
|
.type = IIO_TEMP,
|
||||||
|
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
|
||||||
|
BIT(IIO_CHAN_INFO_SCALE) |
|
||||||
|
BIT(IIO_CHAN_INFO_OFFSET),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static int iqs620_temp_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct iqs62x_core *iqs62x = dev_get_drvdata(pdev->dev.parent);
|
||||||
|
struct iio_dev *indio_dev;
|
||||||
|
|
||||||
|
indio_dev = devm_iio_device_alloc(&pdev->dev, 0);
|
||||||
|
if (!indio_dev)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
iio_device_set_drvdata(indio_dev, iqs62x);
|
||||||
|
|
||||||
|
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||||
|
indio_dev->dev.parent = &pdev->dev;
|
||||||
|
indio_dev->channels = iqs620_temp_channels;
|
||||||
|
indio_dev->num_channels = ARRAY_SIZE(iqs620_temp_channels);
|
||||||
|
indio_dev->name = iqs62x->dev_desc->dev_name;
|
||||||
|
indio_dev->info = &iqs620_temp_info;
|
||||||
|
|
||||||
|
return devm_iio_device_register(&pdev->dev, indio_dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct platform_driver iqs620_temp_platform_driver = {
|
||||||
|
.driver = {
|
||||||
|
.name = "iqs620at-temp",
|
||||||
|
},
|
||||||
|
.probe = iqs620_temp_probe,
|
||||||
|
};
|
||||||
|
module_platform_driver(iqs620_temp_platform_driver);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Jeff LaBundy <jeff@labundy.com>");
|
||||||
|
MODULE_DESCRIPTION("Azoteq IQS620AT Temperature Sensor");
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
MODULE_ALIAS("platform:iqs620at-temp");
|
|
@ -663,6 +663,16 @@ config KEYBOARD_IPAQ_MICRO
|
||||||
To compile this driver as a module, choose M here: the
|
To compile this driver as a module, choose M here: the
|
||||||
module will be called ipaq-micro-keys.
|
module will be called ipaq-micro-keys.
|
||||||
|
|
||||||
|
config KEYBOARD_IQS62X
|
||||||
|
tristate "Azoteq IQS620A/621/622/624/625 keys and switches"
|
||||||
|
depends on MFD_IQS62X
|
||||||
|
help
|
||||||
|
Say Y here to enable key and switch support for the Azoteq IQS620A,
|
||||||
|
IQS621, IQS622, IQS624 and IQS625 multi-function sensors.
|
||||||
|
|
||||||
|
To compile this driver as a module, choose M here: the module will
|
||||||
|
be called iqs62x-keys.
|
||||||
|
|
||||||
config KEYBOARD_OMAP
|
config KEYBOARD_OMAP
|
||||||
tristate "TI OMAP keypad support"
|
tristate "TI OMAP keypad support"
|
||||||
depends on ARCH_OMAP1
|
depends on ARCH_OMAP1
|
||||||
|
|
|
@ -28,6 +28,7 @@ obj-$(CONFIG_KEYBOARD_TCA8418) += tca8418_keypad.o
|
||||||
obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o
|
obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o
|
||||||
obj-$(CONFIG_KEYBOARD_HIL_OLD) += hilkbd.o
|
obj-$(CONFIG_KEYBOARD_HIL_OLD) += hilkbd.o
|
||||||
obj-$(CONFIG_KEYBOARD_IPAQ_MICRO) += ipaq-micro-keys.o
|
obj-$(CONFIG_KEYBOARD_IPAQ_MICRO) += ipaq-micro-keys.o
|
||||||
|
obj-$(CONFIG_KEYBOARD_IQS62X) += iqs62x-keys.o
|
||||||
obj-$(CONFIG_KEYBOARD_IMX) += imx_keypad.o
|
obj-$(CONFIG_KEYBOARD_IMX) += imx_keypad.o
|
||||||
obj-$(CONFIG_KEYBOARD_IMX_SC_KEY) += imx_sc_key.o
|
obj-$(CONFIG_KEYBOARD_IMX_SC_KEY) += imx_sc_key.o
|
||||||
obj-$(CONFIG_KEYBOARD_HP6XX) += jornada680_kbd.o
|
obj-$(CONFIG_KEYBOARD_HP6XX) += jornada680_kbd.o
|
||||||
|
|
|
@ -0,0 +1,335 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
|
/*
|
||||||
|
* Azoteq IQS620A/621/622/624/625 Keys and Switches
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019 Jeff LaBundy <jeff@labundy.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/device.h>
|
||||||
|
#include <linux/input.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/mfd/iqs62x.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/notifier.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/property.h>
|
||||||
|
#include <linux/regmap.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
|
||||||
|
enum {
|
||||||
|
IQS62X_SW_HALL_N,
|
||||||
|
IQS62X_SW_HALL_S,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char * const iqs62x_switch_names[] = {
|
||||||
|
[IQS62X_SW_HALL_N] = "hall-switch-north",
|
||||||
|
[IQS62X_SW_HALL_S] = "hall-switch-south",
|
||||||
|
};
|
||||||
|
|
||||||
|
struct iqs62x_switch_desc {
|
||||||
|
enum iqs62x_event_flag flag;
|
||||||
|
unsigned int code;
|
||||||
|
bool enabled;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct iqs62x_keys_private {
|
||||||
|
struct iqs62x_core *iqs62x;
|
||||||
|
struct input_dev *input;
|
||||||
|
struct notifier_block notifier;
|
||||||
|
struct iqs62x_switch_desc switches[ARRAY_SIZE(iqs62x_switch_names)];
|
||||||
|
unsigned int keycode[IQS62X_NUM_KEYS];
|
||||||
|
unsigned int keycodemax;
|
||||||
|
u8 interval;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int iqs62x_keys_parse_prop(struct platform_device *pdev,
|
||||||
|
struct iqs62x_keys_private *iqs62x_keys)
|
||||||
|
{
|
||||||
|
struct fwnode_handle *child;
|
||||||
|
unsigned int val;
|
||||||
|
int ret, i;
|
||||||
|
|
||||||
|
ret = device_property_count_u32(&pdev->dev, "linux,keycodes");
|
||||||
|
if (ret > IQS62X_NUM_KEYS) {
|
||||||
|
dev_err(&pdev->dev, "Too many keycodes present\n");
|
||||||
|
return -EINVAL;
|
||||||
|
} else if (ret < 0) {
|
||||||
|
dev_err(&pdev->dev, "Failed to count keycodes: %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
iqs62x_keys->keycodemax = ret;
|
||||||
|
|
||||||
|
ret = device_property_read_u32_array(&pdev->dev, "linux,keycodes",
|
||||||
|
iqs62x_keys->keycode,
|
||||||
|
iqs62x_keys->keycodemax);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(&pdev->dev, "Failed to read keycodes: %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(iqs62x_keys->switches); i++) {
|
||||||
|
child = device_get_named_child_node(&pdev->dev,
|
||||||
|
iqs62x_switch_names[i]);
|
||||||
|
if (!child)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
ret = fwnode_property_read_u32(child, "linux,code", &val);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(&pdev->dev, "Failed to read switch code: %d\n",
|
||||||
|
ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
iqs62x_keys->switches[i].code = val;
|
||||||
|
iqs62x_keys->switches[i].enabled = true;
|
||||||
|
|
||||||
|
if (fwnode_property_present(child, "azoteq,use-prox"))
|
||||||
|
iqs62x_keys->switches[i].flag = (i == IQS62X_SW_HALL_N ?
|
||||||
|
IQS62X_EVENT_HALL_N_P :
|
||||||
|
IQS62X_EVENT_HALL_S_P);
|
||||||
|
else
|
||||||
|
iqs62x_keys->switches[i].flag = (i == IQS62X_SW_HALL_N ?
|
||||||
|
IQS62X_EVENT_HALL_N_T :
|
||||||
|
IQS62X_EVENT_HALL_S_T);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int iqs62x_keys_init(struct iqs62x_keys_private *iqs62x_keys)
|
||||||
|
{
|
||||||
|
struct iqs62x_core *iqs62x = iqs62x_keys->iqs62x;
|
||||||
|
enum iqs62x_event_flag flag;
|
||||||
|
unsigned int event_reg, val;
|
||||||
|
unsigned int event_mask = 0;
|
||||||
|
int ret, i;
|
||||||
|
|
||||||
|
switch (iqs62x->dev_desc->prod_num) {
|
||||||
|
case IQS620_PROD_NUM:
|
||||||
|
case IQS621_PROD_NUM:
|
||||||
|
case IQS622_PROD_NUM:
|
||||||
|
event_reg = IQS620_GLBL_EVENT_MASK;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Discreet button, hysteresis and SAR UI flags represent keys
|
||||||
|
* and are unmasked if mapped to a valid keycode.
|
||||||
|
*/
|
||||||
|
for (i = 0; i < iqs62x_keys->keycodemax; i++) {
|
||||||
|
if (iqs62x_keys->keycode[i] == KEY_RESERVED)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (iqs62x_events[i].reg == IQS62X_EVENT_PROX)
|
||||||
|
event_mask |= iqs62x->dev_desc->prox_mask;
|
||||||
|
else if (iqs62x_events[i].reg == IQS62X_EVENT_HYST)
|
||||||
|
event_mask |= (iqs62x->dev_desc->hyst_mask |
|
||||||
|
iqs62x->dev_desc->sar_mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = regmap_read(iqs62x->regmap, iqs62x->dev_desc->hall_flags,
|
||||||
|
&val);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Hall UI flags represent switches and are unmasked if their
|
||||||
|
* corresponding child nodes are present.
|
||||||
|
*/
|
||||||
|
for (i = 0; i < ARRAY_SIZE(iqs62x_keys->switches); i++) {
|
||||||
|
if (!(iqs62x_keys->switches[i].enabled))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
flag = iqs62x_keys->switches[i].flag;
|
||||||
|
|
||||||
|
if (iqs62x_events[flag].reg != IQS62X_EVENT_HALL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
event_mask |= iqs62x->dev_desc->hall_mask;
|
||||||
|
|
||||||
|
input_report_switch(iqs62x_keys->input,
|
||||||
|
iqs62x_keys->switches[i].code,
|
||||||
|
(val & iqs62x_events[flag].mask) ==
|
||||||
|
iqs62x_events[flag].val);
|
||||||
|
}
|
||||||
|
|
||||||
|
input_sync(iqs62x_keys->input);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IQS624_PROD_NUM:
|
||||||
|
event_reg = IQS624_HALL_UI;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Interval change events represent keys and are unmasked if
|
||||||
|
* either wheel movement flag is mapped to a valid keycode.
|
||||||
|
*/
|
||||||
|
if (iqs62x_keys->keycode[IQS62X_EVENT_WHEEL_UP] != KEY_RESERVED)
|
||||||
|
event_mask |= IQS624_HALL_UI_INT_EVENT;
|
||||||
|
|
||||||
|
if (iqs62x_keys->keycode[IQS62X_EVENT_WHEEL_DN] != KEY_RESERVED)
|
||||||
|
event_mask |= IQS624_HALL_UI_INT_EVENT;
|
||||||
|
|
||||||
|
ret = regmap_read(iqs62x->regmap, iqs62x->dev_desc->interval,
|
||||||
|
&val);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
iqs62x_keys->interval = val;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return regmap_update_bits(iqs62x->regmap, event_reg, event_mask, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int iqs62x_keys_notifier(struct notifier_block *notifier,
|
||||||
|
unsigned long event_flags, void *context)
|
||||||
|
{
|
||||||
|
struct iqs62x_event_data *event_data = context;
|
||||||
|
struct iqs62x_keys_private *iqs62x_keys;
|
||||||
|
int ret, i;
|
||||||
|
|
||||||
|
iqs62x_keys = container_of(notifier, struct iqs62x_keys_private,
|
||||||
|
notifier);
|
||||||
|
|
||||||
|
if (event_flags & BIT(IQS62X_EVENT_SYS_RESET)) {
|
||||||
|
ret = iqs62x_keys_init(iqs62x_keys);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(iqs62x_keys->input->dev.parent,
|
||||||
|
"Failed to re-initialize device: %d\n", ret);
|
||||||
|
return NOTIFY_BAD;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NOTIFY_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < iqs62x_keys->keycodemax; i++) {
|
||||||
|
if (iqs62x_events[i].reg == IQS62X_EVENT_WHEEL &&
|
||||||
|
event_data->interval == iqs62x_keys->interval)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
input_report_key(iqs62x_keys->input, iqs62x_keys->keycode[i],
|
||||||
|
event_flags & BIT(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(iqs62x_keys->switches); i++)
|
||||||
|
if (iqs62x_keys->switches[i].enabled)
|
||||||
|
input_report_switch(iqs62x_keys->input,
|
||||||
|
iqs62x_keys->switches[i].code,
|
||||||
|
event_flags &
|
||||||
|
BIT(iqs62x_keys->switches[i].flag));
|
||||||
|
|
||||||
|
input_sync(iqs62x_keys->input);
|
||||||
|
|
||||||
|
if (event_data->interval == iqs62x_keys->interval)
|
||||||
|
return NOTIFY_OK;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Each frame contains at most one wheel event (up or down), in which
|
||||||
|
* case a complementary release cycle is emulated.
|
||||||
|
*/
|
||||||
|
if (event_flags & BIT(IQS62X_EVENT_WHEEL_UP)) {
|
||||||
|
input_report_key(iqs62x_keys->input,
|
||||||
|
iqs62x_keys->keycode[IQS62X_EVENT_WHEEL_UP],
|
||||||
|
0);
|
||||||
|
input_sync(iqs62x_keys->input);
|
||||||
|
} else if (event_flags & BIT(IQS62X_EVENT_WHEEL_DN)) {
|
||||||
|
input_report_key(iqs62x_keys->input,
|
||||||
|
iqs62x_keys->keycode[IQS62X_EVENT_WHEEL_DN],
|
||||||
|
0);
|
||||||
|
input_sync(iqs62x_keys->input);
|
||||||
|
}
|
||||||
|
|
||||||
|
iqs62x_keys->interval = event_data->interval;
|
||||||
|
|
||||||
|
return NOTIFY_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int iqs62x_keys_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct iqs62x_core *iqs62x = dev_get_drvdata(pdev->dev.parent);
|
||||||
|
struct iqs62x_keys_private *iqs62x_keys;
|
||||||
|
struct input_dev *input;
|
||||||
|
int ret, i;
|
||||||
|
|
||||||
|
iqs62x_keys = devm_kzalloc(&pdev->dev, sizeof(*iqs62x_keys),
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (!iqs62x_keys)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
platform_set_drvdata(pdev, iqs62x_keys);
|
||||||
|
|
||||||
|
ret = iqs62x_keys_parse_prop(pdev, iqs62x_keys);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
input = devm_input_allocate_device(&pdev->dev);
|
||||||
|
if (!input)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
input->keycodemax = iqs62x_keys->keycodemax;
|
||||||
|
input->keycode = iqs62x_keys->keycode;
|
||||||
|
input->keycodesize = sizeof(*iqs62x_keys->keycode);
|
||||||
|
|
||||||
|
input->name = iqs62x->dev_desc->dev_name;
|
||||||
|
input->id.bustype = BUS_I2C;
|
||||||
|
|
||||||
|
for (i = 0; i < iqs62x_keys->keycodemax; i++)
|
||||||
|
if (iqs62x_keys->keycode[i] != KEY_RESERVED)
|
||||||
|
input_set_capability(input, EV_KEY,
|
||||||
|
iqs62x_keys->keycode[i]);
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(iqs62x_keys->switches); i++)
|
||||||
|
if (iqs62x_keys->switches[i].enabled)
|
||||||
|
input_set_capability(input, EV_SW,
|
||||||
|
iqs62x_keys->switches[i].code);
|
||||||
|
|
||||||
|
iqs62x_keys->iqs62x = iqs62x;
|
||||||
|
iqs62x_keys->input = input;
|
||||||
|
|
||||||
|
ret = iqs62x_keys_init(iqs62x_keys);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(&pdev->dev, "Failed to initialize device: %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = input_register_device(iqs62x_keys->input);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(&pdev->dev, "Failed to register device: %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
iqs62x_keys->notifier.notifier_call = iqs62x_keys_notifier;
|
||||||
|
ret = blocking_notifier_chain_register(&iqs62x_keys->iqs62x->nh,
|
||||||
|
&iqs62x_keys->notifier);
|
||||||
|
if (ret)
|
||||||
|
dev_err(&pdev->dev, "Failed to register notifier: %d\n", ret);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int iqs62x_keys_remove(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct iqs62x_keys_private *iqs62x_keys = platform_get_drvdata(pdev);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = blocking_notifier_chain_unregister(&iqs62x_keys->iqs62x->nh,
|
||||||
|
&iqs62x_keys->notifier);
|
||||||
|
if (ret)
|
||||||
|
dev_err(&pdev->dev, "Failed to unregister notifier: %d\n", ret);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct platform_driver iqs62x_keys_platform_driver = {
|
||||||
|
.driver = {
|
||||||
|
.name = "iqs62x-keys",
|
||||||
|
},
|
||||||
|
.probe = iqs62x_keys_probe,
|
||||||
|
.remove = iqs62x_keys_remove,
|
||||||
|
};
|
||||||
|
module_platform_driver(iqs62x_keys_platform_driver);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Jeff LaBundy <jeff@labundy.com>");
|
||||||
|
MODULE_DESCRIPTION("Azoteq IQS620A/621/622/624/625 Keys and Switches");
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
MODULE_ALIAS("platform:iqs62x-keys");
|
|
@ -642,6 +642,19 @@ config MFD_IPAQ_MICRO
|
||||||
AT90LS8535 microcontroller flashed with a special iPAQ
|
AT90LS8535 microcontroller flashed with a special iPAQ
|
||||||
firmware using the custom protocol implemented in this driver.
|
firmware using the custom protocol implemented in this driver.
|
||||||
|
|
||||||
|
config MFD_IQS62X
|
||||||
|
tristate "Azoteq IQS620A/621/622/624/625 core support"
|
||||||
|
depends on I2C
|
||||||
|
select MFD_CORE
|
||||||
|
select REGMAP_I2C
|
||||||
|
help
|
||||||
|
Say Y here if you want to build core support for the Azoteq IQS620A,
|
||||||
|
IQS621, IQS622, IQS624 and IQS625 multi-function sensors. Additional
|
||||||
|
options must be selected to enable device-specific functions.
|
||||||
|
|
||||||
|
To compile this driver as a module, choose M here: the module will
|
||||||
|
be called iqs62x.
|
||||||
|
|
||||||
config MFD_JANZ_CMODIO
|
config MFD_JANZ_CMODIO
|
||||||
tristate "Janz CMOD-IO PCI MODULbus Carrier Board"
|
tristate "Janz CMOD-IO PCI MODULbus Carrier Board"
|
||||||
select MFD_CORE
|
select MFD_CORE
|
||||||
|
@ -893,6 +906,7 @@ config MFD_CPCAP
|
||||||
tristate "Support for Motorola CPCAP"
|
tristate "Support for Motorola CPCAP"
|
||||||
depends on SPI
|
depends on SPI
|
||||||
depends on OF || COMPILE_TEST
|
depends on OF || COMPILE_TEST
|
||||||
|
select MFD_CORE
|
||||||
select REGMAP_SPI
|
select REGMAP_SPI
|
||||||
select REGMAP_IRQ
|
select REGMAP_IRQ
|
||||||
help
|
help
|
||||||
|
@ -1058,6 +1072,7 @@ config MFD_RN5T618
|
||||||
depends on OF
|
depends on OF
|
||||||
select MFD_CORE
|
select MFD_CORE
|
||||||
select REGMAP_I2C
|
select REGMAP_I2C
|
||||||
|
select REGMAP_IRQ
|
||||||
help
|
help
|
||||||
Say yes here to add support for the Ricoh RN5T567,
|
Say yes here to add support for the Ricoh RN5T567,
|
||||||
RN5T618, RC5T619 PMIC.
|
RN5T618, RC5T619 PMIC.
|
||||||
|
@ -1201,7 +1216,7 @@ config AB8500_CORE
|
||||||
chip. This connects to U8500 either on the SSP/SPI bus (deprecated
|
chip. This connects to U8500 either on the SSP/SPI bus (deprecated
|
||||||
since hardware version v1.0) or the I2C bus via PRCMU. It also adds
|
since hardware version v1.0) or the I2C bus via PRCMU. It also adds
|
||||||
the irq_chip parts for handling the Mixed Signal chip events.
|
the irq_chip parts for handling the Mixed Signal chip events.
|
||||||
This chip embeds various other multimedia funtionalities as well.
|
This chip embeds various other multimedia functionalities as well.
|
||||||
|
|
||||||
config AB8500_DEBUG
|
config AB8500_DEBUG
|
||||||
bool "Enable debug info via debugfs"
|
bool "Enable debug info via debugfs"
|
||||||
|
@ -1851,7 +1866,7 @@ config MFD_WM8994
|
||||||
has on board GPIO and regulator functionality which is
|
has on board GPIO and regulator functionality which is
|
||||||
supported via the relevant subsystems. This driver provides
|
supported via the relevant subsystems. This driver provides
|
||||||
core support for the WM8994, in order to use the actual
|
core support for the WM8994, in order to use the actual
|
||||||
functionaltiy of the device other drivers must be enabled.
|
functionality of the device other drivers must be enabled.
|
||||||
|
|
||||||
config MFD_WM97xx
|
config MFD_WM97xx
|
||||||
tristate "Wolfson Microelectronics WM97xx"
|
tristate "Wolfson Microelectronics WM97xx"
|
||||||
|
@ -1864,7 +1879,7 @@ config MFD_WM97xx
|
||||||
designed for smartphone applications. As well as audio functionality
|
designed for smartphone applications. As well as audio functionality
|
||||||
it has on board GPIO and a touchscreen functionality which is
|
it has on board GPIO and a touchscreen functionality which is
|
||||||
supported via the relevant subsystems. This driver provides core
|
supported via the relevant subsystems. This driver provides core
|
||||||
support for the WM97xx, in order to use the actual functionaltiy of
|
support for the WM97xx, in order to use the actual functionality of
|
||||||
the device other drivers must be enabled.
|
the device other drivers must be enabled.
|
||||||
|
|
||||||
config MFD_STW481X
|
config MFD_STW481X
|
||||||
|
@ -1957,7 +1972,7 @@ config MFD_STPMIC1
|
||||||
Support for ST Microelectronics STPMIC1 PMIC. STPMIC1 has power on
|
Support for ST Microelectronics STPMIC1 PMIC. STPMIC1 has power on
|
||||||
key, watchdog and regulator functionalities which are supported via
|
key, watchdog and regulator functionalities which are supported via
|
||||||
the relevant subsystems. This driver provides core support for the
|
the relevant subsystems. This driver provides core support for the
|
||||||
STPMIC1. In order to use the actual functionaltiy of the device other
|
STPMIC1. In order to use the actual functionality of the device other
|
||||||
drivers must be enabled.
|
drivers must be enabled.
|
||||||
|
|
||||||
To compile this driver as a module, choose M here: the
|
To compile this driver as a module, choose M here: the
|
||||||
|
|
|
@ -226,6 +226,7 @@ obj-$(CONFIG_MFD_AS3711) += as3711.o
|
||||||
obj-$(CONFIG_MFD_AS3722) += as3722.o
|
obj-$(CONFIG_MFD_AS3722) += as3722.o
|
||||||
obj-$(CONFIG_MFD_STW481X) += stw481x.o
|
obj-$(CONFIG_MFD_STW481X) += stw481x.o
|
||||||
obj-$(CONFIG_MFD_IPAQ_MICRO) += ipaq-micro.o
|
obj-$(CONFIG_MFD_IPAQ_MICRO) += ipaq-micro.o
|
||||||
|
obj-$(CONFIG_MFD_IQS62X) += iqs62x.o
|
||||||
obj-$(CONFIG_MFD_MENF21BMC) += menf21bmc.o
|
obj-$(CONFIG_MFD_MENF21BMC) += menf21bmc.o
|
||||||
obj-$(CONFIG_MFD_HI6421_PMIC) += hi6421-pmic-core.o
|
obj-$(CONFIG_MFD_HI6421_PMIC) += hi6421-pmic-core.o
|
||||||
obj-$(CONFIG_MFD_HI655X_PMIC) += hi655x-pmic.o
|
obj-$(CONFIG_MFD_HI655X_PMIC) += hi655x-pmic.o
|
||||||
|
|
|
@ -221,7 +221,7 @@ static ssize_t aat2870_dump_reg(struct aat2870_data *aat2870, char *buf)
|
||||||
|
|
||||||
count += sprintf(buf, "aat2870 registers\n");
|
count += sprintf(buf, "aat2870 registers\n");
|
||||||
for (addr = 0; addr < AAT2870_REG_NUM; addr++) {
|
for (addr = 0; addr < AAT2870_REG_NUM; addr++) {
|
||||||
count += sprintf(buf + count, "0x%02x: ", addr);
|
count += snprintf(buf + count, PAGE_SIZE - count, "0x%02x: ", addr);
|
||||||
if (count >= PAGE_SIZE - 1)
|
if (count >= PAGE_SIZE - 1)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -211,7 +211,7 @@ static int ec_device_probe(struct platform_device *pdev)
|
||||||
* explicitly added on platforms that don't have the PD notifier ACPI
|
* explicitly added on platforms that don't have the PD notifier ACPI
|
||||||
* device entry defined.
|
* device entry defined.
|
||||||
*/
|
*/
|
||||||
if (IS_ENABLED(CONFIG_OF)) {
|
if (IS_ENABLED(CONFIG_OF) && ec->ec_dev->dev->of_node) {
|
||||||
if (cros_ec_check_features(ec, EC_FEATURE_USB_PD)) {
|
if (cros_ec_check_features(ec, EC_FEATURE_USB_PD)) {
|
||||||
retval = mfd_add_hotplug_devices(ec->dev,
|
retval = mfd_add_hotplug_devices(ec->dev,
|
||||||
cros_usbpd_notify_cells,
|
cros_usbpd_notify_cells,
|
||||||
|
|
|
@ -21,6 +21,9 @@
|
||||||
#define DA9062_REG_EVENT_B_OFFSET 1
|
#define DA9062_REG_EVENT_B_OFFSET 1
|
||||||
#define DA9062_REG_EVENT_C_OFFSET 2
|
#define DA9062_REG_EVENT_C_OFFSET 2
|
||||||
|
|
||||||
|
#define DA9062_IRQ_LOW 0
|
||||||
|
#define DA9062_IRQ_HIGH 1
|
||||||
|
|
||||||
static struct regmap_irq da9061_irqs[] = {
|
static struct regmap_irq da9061_irqs[] = {
|
||||||
/* EVENT A */
|
/* EVENT A */
|
||||||
[DA9061_IRQ_ONKEY] = {
|
[DA9061_IRQ_ONKEY] = {
|
||||||
|
@ -369,6 +372,33 @@ static int da9062_get_device_type(struct da9062 *chip)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static u32 da9062_configure_irq_type(struct da9062 *chip, int irq, u32 *trigger)
|
||||||
|
{
|
||||||
|
u32 irq_type = 0;
|
||||||
|
struct irq_data *irq_data = irq_get_irq_data(irq);
|
||||||
|
|
||||||
|
if (!irq_data) {
|
||||||
|
dev_err(chip->dev, "Invalid IRQ: %d\n", irq);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
*trigger = irqd_get_trigger_type(irq_data);
|
||||||
|
|
||||||
|
switch (*trigger) {
|
||||||
|
case IRQ_TYPE_LEVEL_HIGH:
|
||||||
|
irq_type = DA9062_IRQ_HIGH;
|
||||||
|
break;
|
||||||
|
case IRQ_TYPE_LEVEL_LOW:
|
||||||
|
irq_type = DA9062_IRQ_LOW;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
dev_warn(chip->dev, "Unsupported IRQ type: %d\n", *trigger);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
return regmap_update_bits(chip->regmap, DA9062AA_CONFIG_A,
|
||||||
|
DA9062AA_IRQ_TYPE_MASK,
|
||||||
|
irq_type << DA9062AA_IRQ_TYPE_SHIFT);
|
||||||
|
}
|
||||||
|
|
||||||
static const struct regmap_range da9061_aa_readable_ranges[] = {
|
static const struct regmap_range da9061_aa_readable_ranges[] = {
|
||||||
regmap_reg_range(DA9062AA_PAGE_CON, DA9062AA_STATUS_B),
|
regmap_reg_range(DA9062AA_PAGE_CON, DA9062AA_STATUS_B),
|
||||||
regmap_reg_range(DA9062AA_STATUS_D, DA9062AA_EVENT_C),
|
regmap_reg_range(DA9062AA_STATUS_D, DA9062AA_EVENT_C),
|
||||||
|
@ -388,6 +418,7 @@ static const struct regmap_range da9061_aa_readable_ranges[] = {
|
||||||
regmap_reg_range(DA9062AA_VBUCK1_A, DA9062AA_VBUCK4_A),
|
regmap_reg_range(DA9062AA_VBUCK1_A, DA9062AA_VBUCK4_A),
|
||||||
regmap_reg_range(DA9062AA_VBUCK3_A, DA9062AA_VBUCK3_A),
|
regmap_reg_range(DA9062AA_VBUCK3_A, DA9062AA_VBUCK3_A),
|
||||||
regmap_reg_range(DA9062AA_VLDO1_A, DA9062AA_VLDO4_A),
|
regmap_reg_range(DA9062AA_VLDO1_A, DA9062AA_VLDO4_A),
|
||||||
|
regmap_reg_range(DA9062AA_CONFIG_A, DA9062AA_CONFIG_A),
|
||||||
regmap_reg_range(DA9062AA_VBUCK1_B, DA9062AA_VBUCK4_B),
|
regmap_reg_range(DA9062AA_VBUCK1_B, DA9062AA_VBUCK4_B),
|
||||||
regmap_reg_range(DA9062AA_VBUCK3_B, DA9062AA_VBUCK3_B),
|
regmap_reg_range(DA9062AA_VBUCK3_B, DA9062AA_VBUCK3_B),
|
||||||
regmap_reg_range(DA9062AA_VLDO1_B, DA9062AA_VLDO4_B),
|
regmap_reg_range(DA9062AA_VLDO1_B, DA9062AA_VLDO4_B),
|
||||||
|
@ -417,6 +448,7 @@ static const struct regmap_range da9061_aa_writeable_ranges[] = {
|
||||||
regmap_reg_range(DA9062AA_VBUCK1_A, DA9062AA_VBUCK4_A),
|
regmap_reg_range(DA9062AA_VBUCK1_A, DA9062AA_VBUCK4_A),
|
||||||
regmap_reg_range(DA9062AA_VBUCK3_A, DA9062AA_VBUCK3_A),
|
regmap_reg_range(DA9062AA_VBUCK3_A, DA9062AA_VBUCK3_A),
|
||||||
regmap_reg_range(DA9062AA_VLDO1_A, DA9062AA_VLDO4_A),
|
regmap_reg_range(DA9062AA_VLDO1_A, DA9062AA_VLDO4_A),
|
||||||
|
regmap_reg_range(DA9062AA_CONFIG_A, DA9062AA_CONFIG_A),
|
||||||
regmap_reg_range(DA9062AA_VBUCK1_B, DA9062AA_VBUCK4_B),
|
regmap_reg_range(DA9062AA_VBUCK1_B, DA9062AA_VBUCK4_B),
|
||||||
regmap_reg_range(DA9062AA_VBUCK3_B, DA9062AA_VBUCK3_B),
|
regmap_reg_range(DA9062AA_VBUCK3_B, DA9062AA_VBUCK3_B),
|
||||||
regmap_reg_range(DA9062AA_VLDO1_B, DA9062AA_VLDO4_B),
|
regmap_reg_range(DA9062AA_VLDO1_B, DA9062AA_VLDO4_B),
|
||||||
|
@ -596,6 +628,7 @@ static int da9062_i2c_probe(struct i2c_client *i2c,
|
||||||
const struct regmap_irq_chip *irq_chip;
|
const struct regmap_irq_chip *irq_chip;
|
||||||
const struct regmap_config *config;
|
const struct regmap_config *config;
|
||||||
int cell_num;
|
int cell_num;
|
||||||
|
u32 trigger_type = 0;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
chip = devm_kzalloc(&i2c->dev, sizeof(*chip), GFP_KERNEL);
|
chip = devm_kzalloc(&i2c->dev, sizeof(*chip), GFP_KERNEL);
|
||||||
|
@ -654,10 +687,15 @@ static int da9062_i2c_probe(struct i2c_client *i2c,
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
ret = da9062_configure_irq_type(chip, i2c->irq, &trigger_type);
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(chip->dev, "Failed to configure IRQ type\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
ret = regmap_add_irq_chip(chip->regmap, i2c->irq,
|
ret = regmap_add_irq_chip(chip->regmap, i2c->irq,
|
||||||
IRQF_TRIGGER_LOW | IRQF_ONESHOT | IRQF_SHARED,
|
trigger_type | IRQF_SHARED | IRQF_ONESHOT,
|
||||||
-1, irq_chip,
|
-1, irq_chip, &chip->regmap_irq);
|
||||||
&chip->regmap_irq);
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(chip->dev, "Failed to request IRQ %d: %d\n",
|
dev_err(chip->dev, "Failed to request IRQ %d: %d\n",
|
||||||
i2c->irq, ret);
|
i2c->irq, ret);
|
||||||
|
|
|
@ -90,6 +90,11 @@ struct dln2_mod_rx_slots {
|
||||||
spinlock_t lock;
|
spinlock_t lock;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum dln2_endpoint {
|
||||||
|
DLN2_EP_OUT = 0,
|
||||||
|
DLN2_EP_IN = 1,
|
||||||
|
};
|
||||||
|
|
||||||
struct dln2_dev {
|
struct dln2_dev {
|
||||||
struct usb_device *usb_dev;
|
struct usb_device *usb_dev;
|
||||||
struct usb_interface *interface;
|
struct usb_interface *interface;
|
||||||
|
@ -640,35 +645,56 @@ static int dln2_start_rx_urbs(struct dln2_dev *dln2, gfp_t gfp)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum {
|
||||||
|
DLN2_ACPI_MATCH_GPIO = 0,
|
||||||
|
DLN2_ACPI_MATCH_I2C = 1,
|
||||||
|
DLN2_ACPI_MATCH_SPI = 2,
|
||||||
|
};
|
||||||
|
|
||||||
static struct dln2_platform_data dln2_pdata_gpio = {
|
static struct dln2_platform_data dln2_pdata_gpio = {
|
||||||
.handle = DLN2_HANDLE_GPIO,
|
.handle = DLN2_HANDLE_GPIO,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct mfd_cell_acpi_match dln2_acpi_match_gpio = {
|
||||||
|
.adr = DLN2_ACPI_MATCH_GPIO,
|
||||||
|
};
|
||||||
|
|
||||||
/* Only one I2C port seems to be supported on current hardware */
|
/* Only one I2C port seems to be supported on current hardware */
|
||||||
static struct dln2_platform_data dln2_pdata_i2c = {
|
static struct dln2_platform_data dln2_pdata_i2c = {
|
||||||
.handle = DLN2_HANDLE_I2C,
|
.handle = DLN2_HANDLE_I2C,
|
||||||
.port = 0,
|
.port = 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct mfd_cell_acpi_match dln2_acpi_match_i2c = {
|
||||||
|
.adr = DLN2_ACPI_MATCH_I2C,
|
||||||
|
};
|
||||||
|
|
||||||
/* Only one SPI port supported */
|
/* Only one SPI port supported */
|
||||||
static struct dln2_platform_data dln2_pdata_spi = {
|
static struct dln2_platform_data dln2_pdata_spi = {
|
||||||
.handle = DLN2_HANDLE_SPI,
|
.handle = DLN2_HANDLE_SPI,
|
||||||
.port = 0,
|
.port = 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct mfd_cell_acpi_match dln2_acpi_match_spi = {
|
||||||
|
.adr = DLN2_ACPI_MATCH_SPI,
|
||||||
|
};
|
||||||
|
|
||||||
static const struct mfd_cell dln2_devs[] = {
|
static const struct mfd_cell dln2_devs[] = {
|
||||||
{
|
{
|
||||||
.name = "dln2-gpio",
|
.name = "dln2-gpio",
|
||||||
|
.acpi_match = &dln2_acpi_match_gpio,
|
||||||
.platform_data = &dln2_pdata_gpio,
|
.platform_data = &dln2_pdata_gpio,
|
||||||
.pdata_size = sizeof(struct dln2_platform_data),
|
.pdata_size = sizeof(struct dln2_platform_data),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.name = "dln2-i2c",
|
.name = "dln2-i2c",
|
||||||
|
.acpi_match = &dln2_acpi_match_i2c,
|
||||||
.platform_data = &dln2_pdata_i2c,
|
.platform_data = &dln2_pdata_i2c,
|
||||||
.pdata_size = sizeof(struct dln2_platform_data),
|
.pdata_size = sizeof(struct dln2_platform_data),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.name = "dln2-spi",
|
.name = "dln2-spi",
|
||||||
|
.acpi_match = &dln2_acpi_match_spi,
|
||||||
.platform_data = &dln2_pdata_spi,
|
.platform_data = &dln2_pdata_spi,
|
||||||
.pdata_size = sizeof(struct dln2_platform_data),
|
.pdata_size = sizeof(struct dln2_platform_data),
|
||||||
},
|
},
|
||||||
|
@ -733,10 +759,10 @@ static int dln2_probe(struct usb_interface *interface,
|
||||||
hostif->desc.bNumEndpoints < 2)
|
hostif->desc.bNumEndpoints < 2)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
epin = &hostif->endpoint[0].desc;
|
epout = &hostif->endpoint[DLN2_EP_OUT].desc;
|
||||||
epout = &hostif->endpoint[1].desc;
|
|
||||||
if (!usb_endpoint_is_bulk_out(epout))
|
if (!usb_endpoint_is_bulk_out(epout))
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
epin = &hostif->endpoint[DLN2_EP_IN].desc;
|
||||||
if (!usb_endpoint_is_bulk_in(epin))
|
if (!usb_endpoint_is_bulk_in(epin))
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
|
|
|
@ -139,6 +139,11 @@ static const struct intel_lpss_platform_info cnl_i2c_info = {
|
||||||
.properties = spt_i2c_properties,
|
.properties = spt_i2c_properties,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct intel_lpss_platform_info ehl_i2c_info = {
|
||||||
|
.clk_rate = 100000000,
|
||||||
|
.properties = bxt_i2c_properties,
|
||||||
|
};
|
||||||
|
|
||||||
static const struct pci_device_id intel_lpss_pci_ids[] = {
|
static const struct pci_device_id intel_lpss_pci_ids[] = {
|
||||||
/* CML-LP */
|
/* CML-LP */
|
||||||
{ PCI_VDEVICE(INTEL, 0x02a8), (kernel_ulong_t)&spt_uart_info },
|
{ PCI_VDEVICE(INTEL, 0x02a8), (kernel_ulong_t)&spt_uart_info },
|
||||||
|
@ -231,15 +236,15 @@ static const struct pci_device_id intel_lpss_pci_ids[] = {
|
||||||
{ PCI_VDEVICE(INTEL, 0x4b2a), (kernel_ulong_t)&bxt_info },
|
{ PCI_VDEVICE(INTEL, 0x4b2a), (kernel_ulong_t)&bxt_info },
|
||||||
{ PCI_VDEVICE(INTEL, 0x4b2b), (kernel_ulong_t)&bxt_info },
|
{ PCI_VDEVICE(INTEL, 0x4b2b), (kernel_ulong_t)&bxt_info },
|
||||||
{ PCI_VDEVICE(INTEL, 0x4b37), (kernel_ulong_t)&bxt_info },
|
{ PCI_VDEVICE(INTEL, 0x4b37), (kernel_ulong_t)&bxt_info },
|
||||||
{ PCI_VDEVICE(INTEL, 0x4b44), (kernel_ulong_t)&bxt_i2c_info },
|
{ PCI_VDEVICE(INTEL, 0x4b44), (kernel_ulong_t)&ehl_i2c_info },
|
||||||
{ PCI_VDEVICE(INTEL, 0x4b45), (kernel_ulong_t)&bxt_i2c_info },
|
{ PCI_VDEVICE(INTEL, 0x4b45), (kernel_ulong_t)&ehl_i2c_info },
|
||||||
{ PCI_VDEVICE(INTEL, 0x4b4b), (kernel_ulong_t)&bxt_i2c_info },
|
{ PCI_VDEVICE(INTEL, 0x4b4b), (kernel_ulong_t)&ehl_i2c_info },
|
||||||
{ PCI_VDEVICE(INTEL, 0x4b4c), (kernel_ulong_t)&bxt_i2c_info },
|
{ PCI_VDEVICE(INTEL, 0x4b4c), (kernel_ulong_t)&ehl_i2c_info },
|
||||||
{ PCI_VDEVICE(INTEL, 0x4b4d), (kernel_ulong_t)&bxt_uart_info },
|
{ PCI_VDEVICE(INTEL, 0x4b4d), (kernel_ulong_t)&bxt_uart_info },
|
||||||
{ PCI_VDEVICE(INTEL, 0x4b78), (kernel_ulong_t)&bxt_i2c_info },
|
{ PCI_VDEVICE(INTEL, 0x4b78), (kernel_ulong_t)&ehl_i2c_info },
|
||||||
{ PCI_VDEVICE(INTEL, 0x4b79), (kernel_ulong_t)&bxt_i2c_info },
|
{ PCI_VDEVICE(INTEL, 0x4b79), (kernel_ulong_t)&ehl_i2c_info },
|
||||||
{ PCI_VDEVICE(INTEL, 0x4b7a), (kernel_ulong_t)&bxt_i2c_info },
|
{ PCI_VDEVICE(INTEL, 0x4b7a), (kernel_ulong_t)&ehl_i2c_info },
|
||||||
{ PCI_VDEVICE(INTEL, 0x4b7b), (kernel_ulong_t)&bxt_i2c_info },
|
{ PCI_VDEVICE(INTEL, 0x4b7b), (kernel_ulong_t)&ehl_i2c_info },
|
||||||
/* JSL */
|
/* JSL */
|
||||||
{ PCI_VDEVICE(INTEL, 0x4da8), (kernel_ulong_t)&spt_uart_info },
|
{ PCI_VDEVICE(INTEL, 0x4da8), (kernel_ulong_t)&spt_uart_info },
|
||||||
{ PCI_VDEVICE(INTEL, 0x4da9), (kernel_ulong_t)&spt_uart_info },
|
{ PCI_VDEVICE(INTEL, 0x4da9), (kernel_ulong_t)&spt_uart_info },
|
||||||
|
@ -347,6 +352,16 @@ static const struct pci_device_id intel_lpss_pci_ids[] = {
|
||||||
{ PCI_VDEVICE(INTEL, 0xa36a), (kernel_ulong_t)&cnl_i2c_info },
|
{ PCI_VDEVICE(INTEL, 0xa36a), (kernel_ulong_t)&cnl_i2c_info },
|
||||||
{ PCI_VDEVICE(INTEL, 0xa36b), (kernel_ulong_t)&cnl_i2c_info },
|
{ PCI_VDEVICE(INTEL, 0xa36b), (kernel_ulong_t)&cnl_i2c_info },
|
||||||
{ PCI_VDEVICE(INTEL, 0xa37b), (kernel_ulong_t)&spt_info },
|
{ PCI_VDEVICE(INTEL, 0xa37b), (kernel_ulong_t)&spt_info },
|
||||||
|
/* CML-V */
|
||||||
|
{ PCI_VDEVICE(INTEL, 0xa3a7), (kernel_ulong_t)&spt_uart_info },
|
||||||
|
{ PCI_VDEVICE(INTEL, 0xa3a8), (kernel_ulong_t)&spt_uart_info },
|
||||||
|
{ PCI_VDEVICE(INTEL, 0xa3a9), (kernel_ulong_t)&spt_info },
|
||||||
|
{ PCI_VDEVICE(INTEL, 0xa3aa), (kernel_ulong_t)&spt_info },
|
||||||
|
{ PCI_VDEVICE(INTEL, 0xa3e0), (kernel_ulong_t)&spt_i2c_info },
|
||||||
|
{ PCI_VDEVICE(INTEL, 0xa3e1), (kernel_ulong_t)&spt_i2c_info },
|
||||||
|
{ PCI_VDEVICE(INTEL, 0xa3e2), (kernel_ulong_t)&spt_i2c_info },
|
||||||
|
{ PCI_VDEVICE(INTEL, 0xa3e3), (kernel_ulong_t)&spt_i2c_info },
|
||||||
|
{ PCI_VDEVICE(INTEL, 0xa3e6), (kernel_ulong_t)&spt_uart_info },
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(pci, intel_lpss_pci_ids);
|
MODULE_DEVICE_TABLE(pci, intel_lpss_pci_ids);
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -840,7 +840,7 @@ MODULE_DEVICE_TABLE(of, usbhs_omap_dt_ids);
|
||||||
|
|
||||||
static struct platform_driver usbhs_omap_driver = {
|
static struct platform_driver usbhs_omap_driver = {
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = (char *)usbhs_driver_name,
|
.name = usbhs_driver_name,
|
||||||
.pm = &usbhsomap_dev_pm_ops,
|
.pm = &usbhsomap_dev_pm_ops,
|
||||||
.of_match_table = usbhs_omap_dt_ids,
|
.of_match_table = usbhs_omap_dt_ids,
|
||||||
},
|
},
|
||||||
|
|
|
@ -99,7 +99,7 @@
|
||||||
struct usbtll_omap {
|
struct usbtll_omap {
|
||||||
void __iomem *base;
|
void __iomem *base;
|
||||||
int nch; /* num. of channels */
|
int nch; /* num. of channels */
|
||||||
struct clk *ch_clk[0]; /* must be the last member */
|
struct clk *ch_clk[]; /* must be the last member */
|
||||||
};
|
};
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*/
|
/*-------------------------------------------------------------------------*/
|
||||||
|
@ -304,7 +304,7 @@ MODULE_DEVICE_TABLE(of, usbtll_omap_dt_ids);
|
||||||
|
|
||||||
static struct platform_driver usbtll_omap_driver = {
|
static struct platform_driver usbtll_omap_driver = {
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = (char *)usbtll_driver_name,
|
.name = usbtll_driver_name,
|
||||||
.of_match_table = usbtll_omap_dt_ids,
|
.of_match_table = usbtll_omap_dt_ids,
|
||||||
},
|
},
|
||||||
.probe = usbtll_omap_probe,
|
.probe = usbtll_omap_probe,
|
||||||
|
|
|
@ -76,7 +76,7 @@ struct pm_irq_chip {
|
||||||
unsigned int num_masters;
|
unsigned int num_masters;
|
||||||
const struct pm_irq_data *pm_irq_data;
|
const struct pm_irq_data *pm_irq_data;
|
||||||
/* MUST BE AT THE END OF THIS STRUCT */
|
/* MUST BE AT THE END OF THIS STRUCT */
|
||||||
u8 config[0];
|
u8 config[];
|
||||||
};
|
};
|
||||||
|
|
||||||
static int pm8xxx_read_block_irq(struct pm_irq_chip *chip, unsigned int bp,
|
static int pm8xxx_read_block_irq(struct pm_irq_chip *chip, unsigned int bp,
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/of_device.h>
|
#include <linux/of_device.h>
|
||||||
#include <linux/regmap.h>
|
#include <linux/regmap.h>
|
||||||
#include <linux/syscore_ops.h>
|
|
||||||
|
|
||||||
struct rk808_reg_data {
|
struct rk808_reg_data {
|
||||||
int addr;
|
int addr;
|
||||||
|
@ -186,7 +185,6 @@ static const struct rk808_reg_data rk805_pre_init_reg[] = {
|
||||||
{RK805_BUCK4_CONFIG_REG, RK805_BUCK3_4_ILMAX_MASK,
|
{RK805_BUCK4_CONFIG_REG, RK805_BUCK3_4_ILMAX_MASK,
|
||||||
RK805_BUCK4_ILMAX_3500MA},
|
RK805_BUCK4_ILMAX_3500MA},
|
||||||
{RK805_BUCK4_CONFIG_REG, BUCK_ILMIN_MASK, BUCK_ILMIN_400MA},
|
{RK805_BUCK4_CONFIG_REG, BUCK_ILMIN_MASK, BUCK_ILMIN_400MA},
|
||||||
{RK805_GPIO_IO_POL_REG, SLP_SD_MSK, SLEEP_FUN},
|
|
||||||
{RK805_THERMAL_REG, TEMP_HOTDIE_MSK, TEMP115C},
|
{RK805_THERMAL_REG, TEMP_HOTDIE_MSK, TEMP115C},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -449,88 +447,60 @@ static const struct regmap_irq_chip rk818_irq_chip = {
|
||||||
|
|
||||||
static struct i2c_client *rk808_i2c_client;
|
static struct i2c_client *rk808_i2c_client;
|
||||||
|
|
||||||
static void rk805_device_shutdown(void)
|
static void rk808_pm_power_off(void)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
unsigned int reg, bit;
|
||||||
struct rk808 *rk808 = i2c_get_clientdata(rk808_i2c_client);
|
struct rk808 *rk808 = i2c_get_clientdata(rk808_i2c_client);
|
||||||
|
|
||||||
if (!rk808)
|
switch (rk808->variant) {
|
||||||
|
case RK805_ID:
|
||||||
|
reg = RK805_DEV_CTRL_REG;
|
||||||
|
bit = DEV_OFF;
|
||||||
|
break;
|
||||||
|
case RK808_ID:
|
||||||
|
reg = RK808_DEVCTRL_REG,
|
||||||
|
bit = DEV_OFF_RST;
|
||||||
|
break;
|
||||||
|
case RK818_ID:
|
||||||
|
reg = RK818_DEVCTRL_REG;
|
||||||
|
bit = DEV_OFF;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
ret = regmap_update_bits(rk808->regmap,
|
ret = regmap_update_bits(rk808->regmap, reg, bit, bit);
|
||||||
RK805_DEV_CTRL_REG,
|
|
||||||
DEV_OFF, DEV_OFF);
|
|
||||||
if (ret)
|
if (ret)
|
||||||
dev_err(&rk808_i2c_client->dev, "Failed to shutdown device!\n");
|
dev_err(&rk808_i2c_client->dev, "Failed to shutdown device!\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rk805_device_shutdown_prepare(void)
|
static void rk8xx_shutdown(struct i2c_client *client)
|
||||||
{
|
{
|
||||||
int ret;
|
struct rk808 *rk808 = i2c_get_clientdata(client);
|
||||||
struct rk808 *rk808 = i2c_get_clientdata(rk808_i2c_client);
|
|
||||||
|
|
||||||
if (!rk808)
|
|
||||||
return;
|
|
||||||
|
|
||||||
ret = regmap_update_bits(rk808->regmap,
|
|
||||||
RK805_GPIO_IO_POL_REG,
|
|
||||||
SLP_SD_MSK, SHUTDOWN_FUN);
|
|
||||||
if (ret)
|
|
||||||
dev_err(&rk808_i2c_client->dev, "Failed to shutdown device!\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void rk808_device_shutdown(void)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
struct rk808 *rk808 = i2c_get_clientdata(rk808_i2c_client);
|
|
||||||
|
|
||||||
if (!rk808)
|
|
||||||
return;
|
|
||||||
|
|
||||||
ret = regmap_update_bits(rk808->regmap,
|
|
||||||
RK808_DEVCTRL_REG,
|
|
||||||
DEV_OFF_RST, DEV_OFF_RST);
|
|
||||||
if (ret)
|
|
||||||
dev_err(&rk808_i2c_client->dev, "Failed to shutdown device!\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void rk818_device_shutdown(void)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
struct rk808 *rk808 = i2c_get_clientdata(rk808_i2c_client);
|
|
||||||
|
|
||||||
if (!rk808)
|
|
||||||
return;
|
|
||||||
|
|
||||||
ret = regmap_update_bits(rk808->regmap,
|
|
||||||
RK818_DEVCTRL_REG,
|
|
||||||
DEV_OFF, DEV_OFF);
|
|
||||||
if (ret)
|
|
||||||
dev_err(&rk808_i2c_client->dev, "Failed to shutdown device!\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void rk8xx_syscore_shutdown(void)
|
|
||||||
{
|
|
||||||
struct rk808 *rk808 = i2c_get_clientdata(rk808_i2c_client);
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (system_state == SYSTEM_POWER_OFF &&
|
switch (rk808->variant) {
|
||||||
(rk808->variant == RK809_ID || rk808->variant == RK817_ID)) {
|
case RK805_ID:
|
||||||
|
ret = regmap_update_bits(rk808->regmap,
|
||||||
|
RK805_GPIO_IO_POL_REG,
|
||||||
|
SLP_SD_MSK,
|
||||||
|
SHUTDOWN_FUN);
|
||||||
|
break;
|
||||||
|
case RK809_ID:
|
||||||
|
case RK817_ID:
|
||||||
ret = regmap_update_bits(rk808->regmap,
|
ret = regmap_update_bits(rk808->regmap,
|
||||||
RK817_SYS_CFG(3),
|
RK817_SYS_CFG(3),
|
||||||
RK817_SLPPIN_FUNC_MSK,
|
RK817_SLPPIN_FUNC_MSK,
|
||||||
SLPPIN_DN_FUN);
|
SLPPIN_DN_FUN);
|
||||||
if (ret) {
|
break;
|
||||||
dev_warn(&rk808_i2c_client->dev,
|
default:
|
||||||
"Cannot switch to power down function\n");
|
return;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if (ret)
|
||||||
|
dev_warn(&client->dev,
|
||||||
|
"Cannot switch to power down function\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct syscore_ops rk808_syscore_ops = {
|
|
||||||
.shutdown = rk8xx_syscore_shutdown,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct of_device_id rk808_of_match[] = {
|
static const struct of_device_id rk808_of_match[] = {
|
||||||
{ .compatible = "rockchip,rk805" },
|
{ .compatible = "rockchip,rk805" },
|
||||||
{ .compatible = "rockchip,rk808" },
|
{ .compatible = "rockchip,rk808" },
|
||||||
|
@ -550,7 +520,7 @@ static int rk808_probe(struct i2c_client *client,
|
||||||
const struct mfd_cell *cells;
|
const struct mfd_cell *cells;
|
||||||
int nr_pre_init_regs;
|
int nr_pre_init_regs;
|
||||||
int nr_cells;
|
int nr_cells;
|
||||||
int pm_off = 0, msb, lsb;
|
int msb, lsb;
|
||||||
unsigned char pmic_id_msb, pmic_id_lsb;
|
unsigned char pmic_id_msb, pmic_id_lsb;
|
||||||
int ret;
|
int ret;
|
||||||
int i;
|
int i;
|
||||||
|
@ -594,8 +564,6 @@ static int rk808_probe(struct i2c_client *client,
|
||||||
nr_pre_init_regs = ARRAY_SIZE(rk805_pre_init_reg);
|
nr_pre_init_regs = ARRAY_SIZE(rk805_pre_init_reg);
|
||||||
cells = rk805s;
|
cells = rk805s;
|
||||||
nr_cells = ARRAY_SIZE(rk805s);
|
nr_cells = ARRAY_SIZE(rk805s);
|
||||||
rk808->pm_pwroff_fn = rk805_device_shutdown;
|
|
||||||
rk808->pm_pwroff_prep_fn = rk805_device_shutdown_prepare;
|
|
||||||
break;
|
break;
|
||||||
case RK808_ID:
|
case RK808_ID:
|
||||||
rk808->regmap_cfg = &rk808_regmap_config;
|
rk808->regmap_cfg = &rk808_regmap_config;
|
||||||
|
@ -604,7 +572,6 @@ static int rk808_probe(struct i2c_client *client,
|
||||||
nr_pre_init_regs = ARRAY_SIZE(rk808_pre_init_reg);
|
nr_pre_init_regs = ARRAY_SIZE(rk808_pre_init_reg);
|
||||||
cells = rk808s;
|
cells = rk808s;
|
||||||
nr_cells = ARRAY_SIZE(rk808s);
|
nr_cells = ARRAY_SIZE(rk808s);
|
||||||
rk808->pm_pwroff_fn = rk808_device_shutdown;
|
|
||||||
break;
|
break;
|
||||||
case RK818_ID:
|
case RK818_ID:
|
||||||
rk808->regmap_cfg = &rk818_regmap_config;
|
rk808->regmap_cfg = &rk818_regmap_config;
|
||||||
|
@ -613,7 +580,6 @@ static int rk808_probe(struct i2c_client *client,
|
||||||
nr_pre_init_regs = ARRAY_SIZE(rk818_pre_init_reg);
|
nr_pre_init_regs = ARRAY_SIZE(rk818_pre_init_reg);
|
||||||
cells = rk818s;
|
cells = rk818s;
|
||||||
nr_cells = ARRAY_SIZE(rk818s);
|
nr_cells = ARRAY_SIZE(rk818s);
|
||||||
rk808->pm_pwroff_fn = rk818_device_shutdown;
|
|
||||||
break;
|
break;
|
||||||
case RK809_ID:
|
case RK809_ID:
|
||||||
case RK817_ID:
|
case RK817_ID:
|
||||||
|
@ -623,7 +589,6 @@ static int rk808_probe(struct i2c_client *client,
|
||||||
nr_pre_init_regs = ARRAY_SIZE(rk817_pre_init_reg);
|
nr_pre_init_regs = ARRAY_SIZE(rk817_pre_init_reg);
|
||||||
cells = rk817s;
|
cells = rk817s;
|
||||||
nr_cells = ARRAY_SIZE(rk817s);
|
nr_cells = ARRAY_SIZE(rk817s);
|
||||||
register_syscore_ops(&rk808_syscore_ops);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
dev_err(&client->dev, "Unsupported RK8XX ID %lu\n",
|
dev_err(&client->dev, "Unsupported RK8XX ID %lu\n",
|
||||||
|
@ -674,17 +639,9 @@ static int rk808_probe(struct i2c_client *client,
|
||||||
goto err_irq;
|
goto err_irq;
|
||||||
}
|
}
|
||||||
|
|
||||||
pm_off = of_property_read_bool(np,
|
if (of_property_read_bool(np, "rockchip,system-power-controller")) {
|
||||||
"rockchip,system-power-controller");
|
|
||||||
if (pm_off && !pm_power_off) {
|
|
||||||
rk808_i2c_client = client;
|
rk808_i2c_client = client;
|
||||||
pm_power_off = rk808->pm_pwroff_fn;
|
pm_power_off = rk808_pm_power_off;
|
||||||
}
|
|
||||||
|
|
||||||
if (pm_off && !pm_power_off_prepare) {
|
|
||||||
if (!rk808_i2c_client)
|
|
||||||
rk808_i2c_client = client;
|
|
||||||
pm_power_off_prepare = rk808->pm_pwroff_prep_fn;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -704,25 +661,24 @@ static int rk808_remove(struct i2c_client *client)
|
||||||
* pm_power_off may points to a function from another module.
|
* pm_power_off may points to a function from another module.
|
||||||
* Check if the pointer is set by us and only then overwrite it.
|
* Check if the pointer is set by us and only then overwrite it.
|
||||||
*/
|
*/
|
||||||
if (rk808->pm_pwroff_fn && pm_power_off == rk808->pm_pwroff_fn)
|
if (pm_power_off == rk808_pm_power_off)
|
||||||
pm_power_off = NULL;
|
pm_power_off = NULL;
|
||||||
|
|
||||||
/**
|
|
||||||
* As above, check if the pointer is set by us before overwrite.
|
|
||||||
*/
|
|
||||||
if (rk808->pm_pwroff_prep_fn &&
|
|
||||||
pm_power_off_prepare == rk808->pm_pwroff_prep_fn)
|
|
||||||
pm_power_off_prepare = NULL;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __maybe_unused rk8xx_suspend(struct device *dev)
|
static int __maybe_unused rk8xx_suspend(struct device *dev)
|
||||||
{
|
{
|
||||||
struct rk808 *rk808 = i2c_get_clientdata(rk808_i2c_client);
|
struct rk808 *rk808 = i2c_get_clientdata(to_i2c_client(dev));
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
switch (rk808->variant) {
|
switch (rk808->variant) {
|
||||||
|
case RK805_ID:
|
||||||
|
ret = regmap_update_bits(rk808->regmap,
|
||||||
|
RK805_GPIO_IO_POL_REG,
|
||||||
|
SLP_SD_MSK,
|
||||||
|
SLEEP_FUN);
|
||||||
|
break;
|
||||||
case RK809_ID:
|
case RK809_ID:
|
||||||
case RK817_ID:
|
case RK817_ID:
|
||||||
ret = regmap_update_bits(rk808->regmap,
|
ret = regmap_update_bits(rk808->regmap,
|
||||||
|
@ -739,7 +695,7 @@ static int __maybe_unused rk8xx_suspend(struct device *dev)
|
||||||
|
|
||||||
static int __maybe_unused rk8xx_resume(struct device *dev)
|
static int __maybe_unused rk8xx_resume(struct device *dev)
|
||||||
{
|
{
|
||||||
struct rk808 *rk808 = i2c_get_clientdata(rk808_i2c_client);
|
struct rk808 *rk808 = i2c_get_clientdata(to_i2c_client(dev));
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
switch (rk808->variant) {
|
switch (rk808->variant) {
|
||||||
|
@ -766,6 +722,7 @@ static struct i2c_driver rk808_i2c_driver = {
|
||||||
},
|
},
|
||||||
.probe = rk808_probe,
|
.probe = rk808_probe,
|
||||||
.remove = rk808_remove,
|
.remove = rk808_remove,
|
||||||
|
.shutdown = rk8xx_shutdown,
|
||||||
};
|
};
|
||||||
|
|
||||||
module_i2c_driver(rk808_i2c_driver);
|
module_i2c_driver(rk808_i2c_driver);
|
||||||
|
|
|
@ -8,10 +8,13 @@
|
||||||
|
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
#include <linux/i2c.h>
|
#include <linux/i2c.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/irq.h>
|
||||||
#include <linux/mfd/core.h>
|
#include <linux/mfd/core.h>
|
||||||
#include <linux/mfd/rn5t618.h>
|
#include <linux/mfd/rn5t618.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/of_device.h>
|
#include <linux/of_device.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
#include <linux/reboot.h>
|
#include <linux/reboot.h>
|
||||||
#include <linux/regmap.h>
|
#include <linux/regmap.h>
|
||||||
|
|
||||||
|
@ -20,6 +23,13 @@ static const struct mfd_cell rn5t618_cells[] = {
|
||||||
{ .name = "rn5t618-wdt" },
|
{ .name = "rn5t618-wdt" },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct mfd_cell rc5t619_cells[] = {
|
||||||
|
{ .name = "rn5t618-adc" },
|
||||||
|
{ .name = "rn5t618-regulator" },
|
||||||
|
{ .name = "rc5t619-rtc" },
|
||||||
|
{ .name = "rn5t618-wdt" },
|
||||||
|
};
|
||||||
|
|
||||||
static bool rn5t618_volatile_reg(struct device *dev, unsigned int reg)
|
static bool rn5t618_volatile_reg(struct device *dev, unsigned int reg)
|
||||||
{
|
{
|
||||||
switch (reg) {
|
switch (reg) {
|
||||||
|
@ -32,6 +42,8 @@ static bool rn5t618_volatile_reg(struct device *dev, unsigned int reg)
|
||||||
case RN5T618_IR_GPF:
|
case RN5T618_IR_GPF:
|
||||||
case RN5T618_MON_IOIN:
|
case RN5T618_MON_IOIN:
|
||||||
case RN5T618_INTMON:
|
case RN5T618_INTMON:
|
||||||
|
case RN5T618_RTC_CTRL1 ... RN5T618_RTC_CTRL2:
|
||||||
|
case RN5T618_RTC_SECONDS ... RN5T618_RTC_YEAR:
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
|
@ -46,9 +58,56 @@ static const struct regmap_config rn5t618_regmap_config = {
|
||||||
.cache_type = REGCACHE_RBTREE,
|
.cache_type = REGCACHE_RBTREE,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct regmap_irq rc5t619_irqs[] = {
|
||||||
|
REGMAP_IRQ_REG(RN5T618_IRQ_SYS, 0, BIT(0)),
|
||||||
|
REGMAP_IRQ_REG(RN5T618_IRQ_DCDC, 0, BIT(1)),
|
||||||
|
REGMAP_IRQ_REG(RN5T618_IRQ_RTC, 0, BIT(2)),
|
||||||
|
REGMAP_IRQ_REG(RN5T618_IRQ_ADC, 0, BIT(3)),
|
||||||
|
REGMAP_IRQ_REG(RN5T618_IRQ_GPIO, 0, BIT(4)),
|
||||||
|
REGMAP_IRQ_REG(RN5T618_IRQ_CHG, 0, BIT(6)),
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct regmap_irq_chip rc5t619_irq_chip = {
|
||||||
|
.name = "rc5t619",
|
||||||
|
.irqs = rc5t619_irqs,
|
||||||
|
.num_irqs = ARRAY_SIZE(rc5t619_irqs),
|
||||||
|
.num_regs = 1,
|
||||||
|
.status_base = RN5T618_INTMON,
|
||||||
|
.mask_base = RN5T618_INTEN,
|
||||||
|
.mask_invert = true,
|
||||||
|
};
|
||||||
|
|
||||||
static struct rn5t618 *rn5t618_pm_power_off;
|
static struct rn5t618 *rn5t618_pm_power_off;
|
||||||
static struct notifier_block rn5t618_restart_handler;
|
static struct notifier_block rn5t618_restart_handler;
|
||||||
|
|
||||||
|
static int rn5t618_irq_init(struct rn5t618 *rn5t618)
|
||||||
|
{
|
||||||
|
const struct regmap_irq_chip *irq_chip = NULL;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!rn5t618->irq)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
switch (rn5t618->variant) {
|
||||||
|
case RC5T619:
|
||||||
|
irq_chip = &rc5t619_irq_chip;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
dev_err(rn5t618->dev, "Currently no IRQ support for variant %d\n",
|
||||||
|
(int)rn5t618->variant);
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = devm_regmap_add_irq_chip(rn5t618->dev, rn5t618->regmap,
|
||||||
|
rn5t618->irq,
|
||||||
|
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
|
||||||
|
0, irq_chip, &rn5t618->irq_data);
|
||||||
|
if (ret)
|
||||||
|
dev_err(rn5t618->dev, "Failed to register IRQ chip\n");
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static void rn5t618_trigger_poweroff_sequence(bool repower)
|
static void rn5t618_trigger_poweroff_sequence(bool repower)
|
||||||
{
|
{
|
||||||
/* disable automatic repower-on */
|
/* disable automatic repower-on */
|
||||||
|
@ -87,8 +146,7 @@ static const struct of_device_id rn5t618_of_match[] = {
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(of, rn5t618_of_match);
|
MODULE_DEVICE_TABLE(of, rn5t618_of_match);
|
||||||
|
|
||||||
static int rn5t618_i2c_probe(struct i2c_client *i2c,
|
static int rn5t618_i2c_probe(struct i2c_client *i2c)
|
||||||
const struct i2c_device_id *id)
|
|
||||||
{
|
{
|
||||||
const struct of_device_id *of_id;
|
const struct of_device_id *of_id;
|
||||||
struct rn5t618 *priv;
|
struct rn5t618 *priv;
|
||||||
|
@ -106,6 +164,8 @@ static int rn5t618_i2c_probe(struct i2c_client *i2c,
|
||||||
|
|
||||||
i2c_set_clientdata(i2c, priv);
|
i2c_set_clientdata(i2c, priv);
|
||||||
priv->variant = (long)of_id->data;
|
priv->variant = (long)of_id->data;
|
||||||
|
priv->irq = i2c->irq;
|
||||||
|
priv->dev = &i2c->dev;
|
||||||
|
|
||||||
priv->regmap = devm_regmap_init_i2c(i2c, &rn5t618_regmap_config);
|
priv->regmap = devm_regmap_init_i2c(i2c, &rn5t618_regmap_config);
|
||||||
if (IS_ERR(priv->regmap)) {
|
if (IS_ERR(priv->regmap)) {
|
||||||
|
@ -114,8 +174,16 @@ static int rn5t618_i2c_probe(struct i2c_client *i2c,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = devm_mfd_add_devices(&i2c->dev, -1, rn5t618_cells,
|
if (priv->variant == RC5T619)
|
||||||
ARRAY_SIZE(rn5t618_cells), NULL, 0, NULL);
|
ret = devm_mfd_add_devices(&i2c->dev, PLATFORM_DEVID_NONE,
|
||||||
|
rc5t619_cells,
|
||||||
|
ARRAY_SIZE(rc5t619_cells),
|
||||||
|
NULL, 0, NULL);
|
||||||
|
else
|
||||||
|
ret = devm_mfd_add_devices(&i2c->dev, PLATFORM_DEVID_NONE,
|
||||||
|
rn5t618_cells,
|
||||||
|
ARRAY_SIZE(rn5t618_cells),
|
||||||
|
NULL, 0, NULL);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(&i2c->dev, "failed to add sub-devices: %d\n", ret);
|
dev_err(&i2c->dev, "failed to add sub-devices: %d\n", ret);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -138,7 +206,7 @@ static int rn5t618_i2c_probe(struct i2c_client *i2c,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return rn5t618_irq_init(priv);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rn5t618_i2c_remove(struct i2c_client *i2c)
|
static int rn5t618_i2c_remove(struct i2c_client *i2c)
|
||||||
|
@ -155,19 +223,38 @@ static int rn5t618_i2c_remove(struct i2c_client *i2c)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct i2c_device_id rn5t618_i2c_id[] = {
|
static int __maybe_unused rn5t618_i2c_suspend(struct device *dev)
|
||||||
{ }
|
{
|
||||||
};
|
struct rn5t618 *priv = dev_get_drvdata(dev);
|
||||||
MODULE_DEVICE_TABLE(i2c, rn5t618_i2c_id);
|
|
||||||
|
if (priv->irq)
|
||||||
|
disable_irq(priv->irq);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __maybe_unused rn5t618_i2c_resume(struct device *dev)
|
||||||
|
{
|
||||||
|
struct rn5t618 *priv = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
if (priv->irq)
|
||||||
|
enable_irq(priv->irq);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static SIMPLE_DEV_PM_OPS(rn5t618_i2c_dev_pm_ops,
|
||||||
|
rn5t618_i2c_suspend,
|
||||||
|
rn5t618_i2c_resume);
|
||||||
|
|
||||||
static struct i2c_driver rn5t618_i2c_driver = {
|
static struct i2c_driver rn5t618_i2c_driver = {
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "rn5t618",
|
.name = "rn5t618",
|
||||||
.of_match_table = of_match_ptr(rn5t618_of_match),
|
.of_match_table = of_match_ptr(rn5t618_of_match),
|
||||||
|
.pm = &rn5t618_i2c_dev_pm_ops,
|
||||||
},
|
},
|
||||||
.probe = rn5t618_i2c_probe,
|
.probe_new = rn5t618_i2c_probe,
|
||||||
.remove = rn5t618_i2c_remove,
|
.remove = rn5t618_i2c_remove,
|
||||||
.id_table = rn5t618_i2c_id,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
module_i2c_driver(rn5t618_i2c_driver);
|
module_i2c_driver(rn5t618_i2c_driver);
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include <linux/of_device.h>
|
#include <linux/of_device.h>
|
||||||
#include <linux/regmap.h>
|
#include <linux/regmap.h>
|
||||||
#include <linux/spi/spi.h>
|
#include <linux/spi/spi.h>
|
||||||
|
#include <uapi/linux/usb/charger.h>
|
||||||
|
|
||||||
#define SPRD_PMIC_INT_MASK_STATUS 0x0
|
#define SPRD_PMIC_INT_MASK_STATUS 0x0
|
||||||
#define SPRD_PMIC_INT_RAW_STATUS 0x4
|
#define SPRD_PMIC_INT_RAW_STATUS 0x4
|
||||||
|
@ -17,6 +18,16 @@
|
||||||
|
|
||||||
#define SPRD_SC2731_IRQ_BASE 0x140
|
#define SPRD_SC2731_IRQ_BASE 0x140
|
||||||
#define SPRD_SC2731_IRQ_NUMS 16
|
#define SPRD_SC2731_IRQ_NUMS 16
|
||||||
|
#define SPRD_SC2731_CHG_DET 0xedc
|
||||||
|
|
||||||
|
/* PMIC charger detection definition */
|
||||||
|
#define SPRD_PMIC_CHG_DET_DELAY_US 200000
|
||||||
|
#define SPRD_PMIC_CHG_DET_TIMEOUT 2000000
|
||||||
|
#define SPRD_PMIC_CHG_DET_DONE BIT(11)
|
||||||
|
#define SPRD_PMIC_SDP_TYPE BIT(7)
|
||||||
|
#define SPRD_PMIC_DCP_TYPE BIT(6)
|
||||||
|
#define SPRD_PMIC_CDP_TYPE BIT(5)
|
||||||
|
#define SPRD_PMIC_CHG_TYPE_MASK GENMASK(7, 5)
|
||||||
|
|
||||||
struct sprd_pmic {
|
struct sprd_pmic {
|
||||||
struct regmap *regmap;
|
struct regmap *regmap;
|
||||||
|
@ -24,12 +35,14 @@ struct sprd_pmic {
|
||||||
struct regmap_irq *irqs;
|
struct regmap_irq *irqs;
|
||||||
struct regmap_irq_chip irq_chip;
|
struct regmap_irq_chip irq_chip;
|
||||||
struct regmap_irq_chip_data *irq_data;
|
struct regmap_irq_chip_data *irq_data;
|
||||||
|
const struct sprd_pmic_data *pdata;
|
||||||
int irq;
|
int irq;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sprd_pmic_data {
|
struct sprd_pmic_data {
|
||||||
u32 irq_base;
|
u32 irq_base;
|
||||||
u32 num_irqs;
|
u32 num_irqs;
|
||||||
|
u32 charger_det;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -40,8 +53,46 @@ struct sprd_pmic_data {
|
||||||
static const struct sprd_pmic_data sc2731_data = {
|
static const struct sprd_pmic_data sc2731_data = {
|
||||||
.irq_base = SPRD_SC2731_IRQ_BASE,
|
.irq_base = SPRD_SC2731_IRQ_BASE,
|
||||||
.num_irqs = SPRD_SC2731_IRQ_NUMS,
|
.num_irqs = SPRD_SC2731_IRQ_NUMS,
|
||||||
|
.charger_det = SPRD_SC2731_CHG_DET,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum usb_charger_type sprd_pmic_detect_charger_type(struct device *dev)
|
||||||
|
{
|
||||||
|
struct spi_device *spi = to_spi_device(dev);
|
||||||
|
struct sprd_pmic *ddata = spi_get_drvdata(spi);
|
||||||
|
const struct sprd_pmic_data *pdata = ddata->pdata;
|
||||||
|
enum usb_charger_type type;
|
||||||
|
u32 val;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = regmap_read_poll_timeout(ddata->regmap, pdata->charger_det, val,
|
||||||
|
(val & SPRD_PMIC_CHG_DET_DONE),
|
||||||
|
SPRD_PMIC_CHG_DET_DELAY_US,
|
||||||
|
SPRD_PMIC_CHG_DET_TIMEOUT);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(&spi->dev, "failed to detect charger type\n");
|
||||||
|
return UNKNOWN_TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (val & SPRD_PMIC_CHG_TYPE_MASK) {
|
||||||
|
case SPRD_PMIC_CDP_TYPE:
|
||||||
|
type = CDP_TYPE;
|
||||||
|
break;
|
||||||
|
case SPRD_PMIC_DCP_TYPE:
|
||||||
|
type = DCP_TYPE;
|
||||||
|
break;
|
||||||
|
case SPRD_PMIC_SDP_TYPE:
|
||||||
|
type = SDP_TYPE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
type = UNKNOWN_TYPE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(sprd_pmic_detect_charger_type);
|
||||||
|
|
||||||
static const struct mfd_cell sprd_pmic_devs[] = {
|
static const struct mfd_cell sprd_pmic_devs[] = {
|
||||||
{
|
{
|
||||||
.name = "sc27xx-wdt",
|
.name = "sc27xx-wdt",
|
||||||
|
@ -181,6 +232,7 @@ static int sprd_pmic_probe(struct spi_device *spi)
|
||||||
spi_set_drvdata(spi, ddata);
|
spi_set_drvdata(spi, ddata);
|
||||||
ddata->dev = &spi->dev;
|
ddata->dev = &spi->dev;
|
||||||
ddata->irq = spi->irq;
|
ddata->irq = spi->irq;
|
||||||
|
ddata->pdata = pdata;
|
||||||
|
|
||||||
ddata->irq_chip.name = dev_name(&spi->dev);
|
ddata->irq_chip.name = dev_name(&spi->dev);
|
||||||
ddata->irq_chip.status_base =
|
ddata->irq_chip.status_base =
|
||||||
|
|
|
@ -590,6 +590,16 @@ config RTC_DRV_RC5T583
|
||||||
This driver can also be built as a module. If so, the module
|
This driver can also be built as a module. If so, the module
|
||||||
will be called rtc-rc5t583.
|
will be called rtc-rc5t583.
|
||||||
|
|
||||||
|
config RTC_DRV_RC5T619
|
||||||
|
tristate "RICOH RC5T619 RTC driver"
|
||||||
|
depends on MFD_RN5T618
|
||||||
|
help
|
||||||
|
If you say yes here you get support for the RTC on the
|
||||||
|
RICOH RC5T619 chips.
|
||||||
|
|
||||||
|
This driver can also be built as a module. If so, the module
|
||||||
|
will be called rtc-rc5t619.
|
||||||
|
|
||||||
config RTC_DRV_S35390A
|
config RTC_DRV_S35390A
|
||||||
tristate "Seiko Instruments S-35390A"
|
tristate "Seiko Instruments S-35390A"
|
||||||
select BITREVERSE
|
select BITREVERSE
|
||||||
|
|
|
@ -133,6 +133,7 @@ obj-$(CONFIG_RTC_DRV_PXA) += rtc-pxa.o
|
||||||
obj-$(CONFIG_RTC_DRV_R7301) += rtc-r7301.o
|
obj-$(CONFIG_RTC_DRV_R7301) += rtc-r7301.o
|
||||||
obj-$(CONFIG_RTC_DRV_R9701) += rtc-r9701.o
|
obj-$(CONFIG_RTC_DRV_R9701) += rtc-r9701.o
|
||||||
obj-$(CONFIG_RTC_DRV_RC5T583) += rtc-rc5t583.o
|
obj-$(CONFIG_RTC_DRV_RC5T583) += rtc-rc5t583.o
|
||||||
|
obj-$(CONFIG_RTC_DRV_RC5T619) += rtc-rc5t619.o
|
||||||
obj-$(CONFIG_RTC_DRV_RK808) += rtc-rk808.o
|
obj-$(CONFIG_RTC_DRV_RK808) += rtc-rk808.o
|
||||||
obj-$(CONFIG_RTC_DRV_RP5C01) += rtc-rp5c01.o
|
obj-$(CONFIG_RTC_DRV_RP5C01) += rtc-rp5c01.o
|
||||||
obj-$(CONFIG_RTC_DRV_RS5C313) += rtc-rs5c313.o
|
obj-$(CONFIG_RTC_DRV_RS5C313) += rtc-rs5c313.o
|
||||||
|
|
|
@ -0,0 +1,444 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
|
/*
|
||||||
|
* drivers/rtc/rtc-rc5t619.c
|
||||||
|
*
|
||||||
|
* Real time clock driver for RICOH RC5T619 power management chip.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019 Andreas Kemnade
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/device.h>
|
||||||
|
#include <linux/errno.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/mfd/rn5t618.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/regmap.h>
|
||||||
|
#include <linux/bcd.h>
|
||||||
|
#include <linux/rtc.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/irqdomain.h>
|
||||||
|
|
||||||
|
struct rc5t619_rtc {
|
||||||
|
int irq;
|
||||||
|
struct rtc_device *rtc;
|
||||||
|
struct rn5t618 *rn5t618;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define CTRL1_ALARM_ENABLED 0x40
|
||||||
|
#define CTRL1_24HR 0x20
|
||||||
|
#define CTRL1_PERIODIC_MASK 0xf
|
||||||
|
|
||||||
|
#define CTRL2_PON 0x10
|
||||||
|
#define CTRL2_ALARM_STATUS 0x80
|
||||||
|
#define CTRL2_CTFG 0x4
|
||||||
|
#define CTRL2_CTC 0x1
|
||||||
|
|
||||||
|
#define MONTH_CENTFLAG 0x80
|
||||||
|
#define HOUR_PMFLAG 0x20
|
||||||
|
#define MDAY_DAL_EXT 0x80
|
||||||
|
|
||||||
|
static uint8_t rtc5t619_12hour_bcd2bin(uint8_t hour)
|
||||||
|
{
|
||||||
|
if (hour & HOUR_PMFLAG) {
|
||||||
|
hour = bcd2bin(hour & ~HOUR_PMFLAG);
|
||||||
|
return hour == 12 ? 12 : 12 + hour;
|
||||||
|
}
|
||||||
|
|
||||||
|
hour = bcd2bin(hour);
|
||||||
|
return hour == 12 ? 0 : hour;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t rtc5t619_12hour_bin2bcd(uint8_t hour)
|
||||||
|
{
|
||||||
|
if (!hour)
|
||||||
|
return 0x12;
|
||||||
|
|
||||||
|
if (hour < 12)
|
||||||
|
return bin2bcd(hour);
|
||||||
|
|
||||||
|
if (hour == 12)
|
||||||
|
return 0x12 | HOUR_PMFLAG;
|
||||||
|
|
||||||
|
return bin2bcd(hour - 12) | HOUR_PMFLAG;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rc5t619_rtc_periodic_disable(struct device *dev)
|
||||||
|
{
|
||||||
|
struct rc5t619_rtc *rtc = dev_get_drvdata(dev);
|
||||||
|
int err;
|
||||||
|
|
||||||
|
/* disable function */
|
||||||
|
err = regmap_update_bits(rtc->rn5t618->regmap,
|
||||||
|
RN5T618_RTC_CTRL1, CTRL1_PERIODIC_MASK, 0);
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
/* clear alarm flag and CTFG */
|
||||||
|
err = regmap_update_bits(rtc->rn5t618->regmap, RN5T618_RTC_CTRL2,
|
||||||
|
CTRL2_ALARM_STATUS | CTRL2_CTFG | CTRL2_CTC,
|
||||||
|
0);
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* things to be done once after power on */
|
||||||
|
static int rc5t619_rtc_pon_setup(struct device *dev)
|
||||||
|
{
|
||||||
|
struct rc5t619_rtc *rtc = dev_get_drvdata(dev);
|
||||||
|
int err;
|
||||||
|
unsigned int reg_data;
|
||||||
|
|
||||||
|
err = regmap_read(rtc->rn5t618->regmap, RN5T618_RTC_CTRL2, ®_data);
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
/* clear VDET PON */
|
||||||
|
reg_data &= ~(CTRL2_PON | CTRL2_CTC | 0x4a); /* 0101-1011 */
|
||||||
|
reg_data |= 0x20; /* 0010-0000 */
|
||||||
|
err = regmap_write(rtc->rn5t618->regmap, RN5T618_RTC_CTRL2, reg_data);
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
/* clearing RTC Adjust register */
|
||||||
|
err = regmap_write(rtc->rn5t618->regmap, RN5T618_RTC_ADJUST, 0);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
return regmap_update_bits(rtc->rn5t618->regmap,
|
||||||
|
RN5T618_RTC_CTRL1,
|
||||||
|
CTRL1_24HR, CTRL1_24HR);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rc5t619_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||||
|
{
|
||||||
|
struct rc5t619_rtc *rtc = dev_get_drvdata(dev);
|
||||||
|
u8 buff[7];
|
||||||
|
int err;
|
||||||
|
int cent_flag;
|
||||||
|
unsigned int ctrl1;
|
||||||
|
unsigned int ctrl2;
|
||||||
|
|
||||||
|
err = regmap_read(rtc->rn5t618->regmap, RN5T618_RTC_CTRL2, &ctrl2);
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
if (ctrl2 & CTRL2_PON)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
err = regmap_read(rtc->rn5t618->regmap, RN5T618_RTC_CTRL1, &ctrl1);
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
err = regmap_bulk_read(rtc->rn5t618->regmap, RN5T618_RTC_SECONDS,
|
||||||
|
buff, sizeof(buff));
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
if (buff[5] & MONTH_CENTFLAG)
|
||||||
|
cent_flag = 1;
|
||||||
|
else
|
||||||
|
cent_flag = 0;
|
||||||
|
|
||||||
|
tm->tm_sec = bcd2bin(buff[0]);
|
||||||
|
tm->tm_min = bcd2bin(buff[1]);
|
||||||
|
|
||||||
|
if (ctrl1 & CTRL1_24HR)
|
||||||
|
tm->tm_hour = bcd2bin(buff[2]);
|
||||||
|
else
|
||||||
|
tm->tm_hour = rtc5t619_12hour_bcd2bin(buff[2]);
|
||||||
|
|
||||||
|
tm->tm_wday = bcd2bin(buff[3]);
|
||||||
|
tm->tm_mday = bcd2bin(buff[4]);
|
||||||
|
tm->tm_mon = bcd2bin(buff[5] & 0x1f) - 1; /* back to system 0-11 */
|
||||||
|
tm->tm_year = bcd2bin(buff[6]) + 100 * cent_flag;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rc5t619_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||||
|
{
|
||||||
|
struct rc5t619_rtc *rtc = dev_get_drvdata(dev);
|
||||||
|
u8 buff[7];
|
||||||
|
int err;
|
||||||
|
int cent_flag;
|
||||||
|
unsigned int ctrl1;
|
||||||
|
unsigned int ctrl2;
|
||||||
|
|
||||||
|
err = regmap_read(rtc->rn5t618->regmap, RN5T618_RTC_CTRL2, &ctrl2);
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
if (ctrl2 & CTRL2_PON)
|
||||||
|
rc5t619_rtc_pon_setup(dev);
|
||||||
|
|
||||||
|
err = regmap_read(rtc->rn5t618->regmap, RN5T618_RTC_CTRL1, &ctrl1);
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
if (tm->tm_year >= 100)
|
||||||
|
cent_flag = 1;
|
||||||
|
else
|
||||||
|
cent_flag = 0;
|
||||||
|
|
||||||
|
buff[0] = bin2bcd(tm->tm_sec);
|
||||||
|
buff[1] = bin2bcd(tm->tm_min);
|
||||||
|
|
||||||
|
if (ctrl1 & CTRL1_24HR)
|
||||||
|
buff[2] = bin2bcd(tm->tm_hour);
|
||||||
|
else
|
||||||
|
buff[2] = rtc5t619_12hour_bin2bcd(tm->tm_hour);
|
||||||
|
|
||||||
|
buff[3] = bin2bcd(tm->tm_wday);
|
||||||
|
buff[4] = bin2bcd(tm->tm_mday);
|
||||||
|
buff[5] = bin2bcd(tm->tm_mon + 1); /* system set 0-11 */
|
||||||
|
buff[6] = bin2bcd(tm->tm_year - cent_flag * 100);
|
||||||
|
|
||||||
|
if (cent_flag)
|
||||||
|
buff[5] |= MONTH_CENTFLAG;
|
||||||
|
|
||||||
|
err = regmap_bulk_write(rtc->rn5t618->regmap, RN5T618_RTC_SECONDS,
|
||||||
|
buff, sizeof(buff));
|
||||||
|
if (err < 0) {
|
||||||
|
dev_err(dev, "failed to program new time: %d\n", err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 0-disable, 1-enable */
|
||||||
|
static int rc5t619_rtc_alarm_enable(struct device *dev, unsigned int enabled)
|
||||||
|
{
|
||||||
|
struct rc5t619_rtc *rtc = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
return regmap_update_bits(rtc->rn5t618->regmap,
|
||||||
|
RN5T618_RTC_CTRL1,
|
||||||
|
CTRL1_ALARM_ENABLED,
|
||||||
|
enabled ? CTRL1_ALARM_ENABLED : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rc5t619_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||||
|
{
|
||||||
|
struct rc5t619_rtc *rtc = dev_get_drvdata(dev);
|
||||||
|
u8 buff[6];
|
||||||
|
unsigned int buff_cent;
|
||||||
|
int err;
|
||||||
|
int cent_flag;
|
||||||
|
unsigned int ctrl1;
|
||||||
|
|
||||||
|
err = regmap_read(rtc->rn5t618->regmap, RN5T618_RTC_CTRL1, &ctrl1);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
err = regmap_read(rtc->rn5t618->regmap, RN5T618_RTC_MONTH, &buff_cent);
|
||||||
|
if (err < 0) {
|
||||||
|
dev_err(dev, "failed to read time: %d\n", err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buff_cent & MONTH_CENTFLAG)
|
||||||
|
cent_flag = 1;
|
||||||
|
else
|
||||||
|
cent_flag = 0;
|
||||||
|
|
||||||
|
err = regmap_bulk_read(rtc->rn5t618->regmap, RN5T618_RTC_ALARM_Y_SEC,
|
||||||
|
buff, sizeof(buff));
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
buff[3] = buff[3] & 0x3f;
|
||||||
|
|
||||||
|
alrm->time.tm_sec = bcd2bin(buff[0]);
|
||||||
|
alrm->time.tm_min = bcd2bin(buff[1]);
|
||||||
|
|
||||||
|
if (ctrl1 & CTRL1_24HR)
|
||||||
|
alrm->time.tm_hour = bcd2bin(buff[2]);
|
||||||
|
else
|
||||||
|
alrm->time.tm_hour = rtc5t619_12hour_bcd2bin(buff[2]);
|
||||||
|
|
||||||
|
alrm->time.tm_mday = bcd2bin(buff[3]);
|
||||||
|
alrm->time.tm_mon = bcd2bin(buff[4]) - 1;
|
||||||
|
alrm->time.tm_year = bcd2bin(buff[5]) + 100 * cent_flag;
|
||||||
|
alrm->enabled = !!(ctrl1 & CTRL1_ALARM_ENABLED);
|
||||||
|
dev_dbg(dev, "read alarm: %ptR\n", &alrm->time);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rc5t619_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||||
|
{
|
||||||
|
struct rc5t619_rtc *rtc = dev_get_drvdata(dev);
|
||||||
|
u8 buff[6];
|
||||||
|
int err;
|
||||||
|
int cent_flag;
|
||||||
|
unsigned int ctrl1;
|
||||||
|
|
||||||
|
err = regmap_read(rtc->rn5t618->regmap, RN5T618_RTC_CTRL1, &ctrl1);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
err = rc5t619_rtc_alarm_enable(dev, 0);
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
if (rtc->irq == -1)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (alrm->enabled == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (alrm->time.tm_year >= 100)
|
||||||
|
cent_flag = 1;
|
||||||
|
else
|
||||||
|
cent_flag = 0;
|
||||||
|
|
||||||
|
alrm->time.tm_mon += 1;
|
||||||
|
buff[0] = bin2bcd(alrm->time.tm_sec);
|
||||||
|
buff[1] = bin2bcd(alrm->time.tm_min);
|
||||||
|
|
||||||
|
if (ctrl1 & CTRL1_24HR)
|
||||||
|
buff[2] = bin2bcd(alrm->time.tm_hour);
|
||||||
|
else
|
||||||
|
buff[2] = rtc5t619_12hour_bin2bcd(alrm->time.tm_hour);
|
||||||
|
|
||||||
|
buff[3] = bin2bcd(alrm->time.tm_mday);
|
||||||
|
buff[4] = bin2bcd(alrm->time.tm_mon);
|
||||||
|
buff[5] = bin2bcd(alrm->time.tm_year - 100 * cent_flag);
|
||||||
|
buff[3] |= MDAY_DAL_EXT;
|
||||||
|
|
||||||
|
err = regmap_bulk_write(rtc->rn5t618->regmap, RN5T618_RTC_ALARM_Y_SEC,
|
||||||
|
buff, sizeof(buff));
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
return rc5t619_rtc_alarm_enable(dev, alrm->enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct rtc_class_ops rc5t619_rtc_ops = {
|
||||||
|
.read_time = rc5t619_rtc_read_time,
|
||||||
|
.set_time = rc5t619_rtc_set_time,
|
||||||
|
.set_alarm = rc5t619_rtc_set_alarm,
|
||||||
|
.read_alarm = rc5t619_rtc_read_alarm,
|
||||||
|
.alarm_irq_enable = rc5t619_rtc_alarm_enable,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int rc5t619_rtc_alarm_flag_clr(struct device *dev)
|
||||||
|
{
|
||||||
|
struct rc5t619_rtc *rtc = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
/* clear alarm-D status bits.*/
|
||||||
|
return regmap_update_bits(rtc->rn5t618->regmap,
|
||||||
|
RN5T618_RTC_CTRL2,
|
||||||
|
CTRL2_ALARM_STATUS | CTRL2_CTC, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static irqreturn_t rc5t619_rtc_irq(int irq, void *data)
|
||||||
|
{
|
||||||
|
struct device *dev = data;
|
||||||
|
struct rc5t619_rtc *rtc = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
rc5t619_rtc_alarm_flag_clr(dev);
|
||||||
|
|
||||||
|
rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_AF);
|
||||||
|
return IRQ_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rc5t619_rtc_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct device *dev = &pdev->dev;
|
||||||
|
struct rn5t618 *rn5t618 = dev_get_drvdata(pdev->dev.parent);
|
||||||
|
struct rc5t619_rtc *rtc;
|
||||||
|
unsigned int ctrl2;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
rtc = devm_kzalloc(dev, sizeof(*rtc), GFP_KERNEL);
|
||||||
|
if (IS_ERR(rtc)) {
|
||||||
|
err = PTR_ERR(rtc);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
rtc->rn5t618 = rn5t618;
|
||||||
|
|
||||||
|
dev_set_drvdata(dev, rtc);
|
||||||
|
rtc->irq = -1;
|
||||||
|
|
||||||
|
if (rn5t618->irq_data)
|
||||||
|
rtc->irq = regmap_irq_get_virq(rn5t618->irq_data,
|
||||||
|
RN5T618_IRQ_RTC);
|
||||||
|
|
||||||
|
if (rtc->irq < 0)
|
||||||
|
rtc->irq = -1;
|
||||||
|
|
||||||
|
err = regmap_read(rtc->rn5t618->regmap, RN5T618_RTC_CTRL2, &ctrl2);
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
/* disable rtc periodic function */
|
||||||
|
err = rc5t619_rtc_periodic_disable(&pdev->dev);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
if (ctrl2 & CTRL2_PON) {
|
||||||
|
err = rc5t619_rtc_alarm_flag_clr(&pdev->dev);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
rtc->rtc = devm_rtc_allocate_device(&pdev->dev);
|
||||||
|
if (IS_ERR(rtc->rtc)) {
|
||||||
|
err = PTR_ERR(rtc->rtc);
|
||||||
|
dev_err(dev, "RTC device register: err %d\n", err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
rtc->rtc->ops = &rc5t619_rtc_ops;
|
||||||
|
rtc->rtc->range_min = RTC_TIMESTAMP_BEGIN_1900;
|
||||||
|
rtc->rtc->range_max = RTC_TIMESTAMP_END_2099;
|
||||||
|
|
||||||
|
/* set interrupt and enable it */
|
||||||
|
if (rtc->irq != -1) {
|
||||||
|
err = devm_request_threaded_irq(&pdev->dev, rtc->irq, NULL,
|
||||||
|
rc5t619_rtc_irq,
|
||||||
|
IRQF_ONESHOT,
|
||||||
|
"rtc-rc5t619",
|
||||||
|
&pdev->dev);
|
||||||
|
if (err < 0) {
|
||||||
|
dev_err(&pdev->dev, "request IRQ:%d fail\n", rtc->irq);
|
||||||
|
rtc->irq = -1;
|
||||||
|
|
||||||
|
err = rc5t619_rtc_alarm_enable(&pdev->dev, 0);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/* enable wake */
|
||||||
|
device_init_wakeup(&pdev->dev, 1);
|
||||||
|
enable_irq_wake(rtc->irq);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* system don't want to using alarm interrupt, so close it */
|
||||||
|
err = rc5t619_rtc_alarm_enable(&pdev->dev, 0);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
dev_warn(&pdev->dev, "rc5t619 interrupt is disabled\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return rtc_register_device(rtc->rtc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct platform_driver rc5t619_rtc_driver = {
|
||||||
|
.driver = {
|
||||||
|
.name = "rc5t619-rtc",
|
||||||
|
},
|
||||||
|
.probe = rc5t619_rtc_probe,
|
||||||
|
};
|
||||||
|
|
||||||
|
module_platform_driver(rc5t619_rtc_driver);
|
||||||
|
MODULE_ALIAS("platform:rc5t619-rtc");
|
||||||
|
MODULE_DESCRIPTION("RICOH RC5T619 RTC driver");
|
||||||
|
MODULE_LICENSE("GPL");
|
|
@ -0,0 +1,139 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||||
|
/*
|
||||||
|
* Azoteq IQS620A/621/622/624/625 Multi-Function Sensors
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019 Jeff LaBundy <jeff@labundy.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LINUX_MFD_IQS62X_H
|
||||||
|
#define __LINUX_MFD_IQS62X_H
|
||||||
|
|
||||||
|
#define IQS620_PROD_NUM 0x41
|
||||||
|
#define IQS621_PROD_NUM 0x46
|
||||||
|
#define IQS622_PROD_NUM 0x42
|
||||||
|
#define IQS624_PROD_NUM 0x43
|
||||||
|
#define IQS625_PROD_NUM 0x4E
|
||||||
|
|
||||||
|
#define IQS621_ALS_FLAGS 0x16
|
||||||
|
#define IQS622_ALS_FLAGS 0x14
|
||||||
|
|
||||||
|
#define IQS624_HALL_UI 0x70
|
||||||
|
#define IQS624_HALL_UI_WHL_EVENT BIT(4)
|
||||||
|
#define IQS624_HALL_UI_INT_EVENT BIT(3)
|
||||||
|
#define IQS624_HALL_UI_AUTO_CAL BIT(2)
|
||||||
|
|
||||||
|
#define IQS624_INTERVAL_DIV 0x7D
|
||||||
|
|
||||||
|
#define IQS620_GLBL_EVENT_MASK 0xD7
|
||||||
|
#define IQS620_GLBL_EVENT_MASK_PMU BIT(6)
|
||||||
|
|
||||||
|
#define IQS62X_NUM_KEYS 16
|
||||||
|
#define IQS62X_NUM_EVENTS (IQS62X_NUM_KEYS + 5)
|
||||||
|
|
||||||
|
#define IQS62X_EVENT_SIZE 10
|
||||||
|
|
||||||
|
enum iqs62x_ui_sel {
|
||||||
|
IQS62X_UI_PROX,
|
||||||
|
IQS62X_UI_SAR1,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum iqs62x_event_reg {
|
||||||
|
IQS62X_EVENT_NONE,
|
||||||
|
IQS62X_EVENT_SYS,
|
||||||
|
IQS62X_EVENT_PROX,
|
||||||
|
IQS62X_EVENT_HYST,
|
||||||
|
IQS62X_EVENT_HALL,
|
||||||
|
IQS62X_EVENT_ALS,
|
||||||
|
IQS62X_EVENT_IR,
|
||||||
|
IQS62X_EVENT_WHEEL,
|
||||||
|
IQS62X_EVENT_INTER,
|
||||||
|
IQS62X_EVENT_UI_LO,
|
||||||
|
IQS62X_EVENT_UI_HI,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum iqs62x_event_flag {
|
||||||
|
/* keys */
|
||||||
|
IQS62X_EVENT_PROX_CH0_T,
|
||||||
|
IQS62X_EVENT_PROX_CH0_P,
|
||||||
|
IQS62X_EVENT_PROX_CH1_T,
|
||||||
|
IQS62X_EVENT_PROX_CH1_P,
|
||||||
|
IQS62X_EVENT_PROX_CH2_T,
|
||||||
|
IQS62X_EVENT_PROX_CH2_P,
|
||||||
|
IQS62X_EVENT_HYST_POS_T,
|
||||||
|
IQS62X_EVENT_HYST_POS_P,
|
||||||
|
IQS62X_EVENT_HYST_NEG_T,
|
||||||
|
IQS62X_EVENT_HYST_NEG_P,
|
||||||
|
IQS62X_EVENT_SAR1_ACT,
|
||||||
|
IQS62X_EVENT_SAR1_QRD,
|
||||||
|
IQS62X_EVENT_SAR1_MOVE,
|
||||||
|
IQS62X_EVENT_SAR1_HALT,
|
||||||
|
IQS62X_EVENT_WHEEL_UP,
|
||||||
|
IQS62X_EVENT_WHEEL_DN,
|
||||||
|
|
||||||
|
/* switches */
|
||||||
|
IQS62X_EVENT_HALL_N_T,
|
||||||
|
IQS62X_EVENT_HALL_N_P,
|
||||||
|
IQS62X_EVENT_HALL_S_T,
|
||||||
|
IQS62X_EVENT_HALL_S_P,
|
||||||
|
|
||||||
|
/* everything else */
|
||||||
|
IQS62X_EVENT_SYS_RESET,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct iqs62x_event_data {
|
||||||
|
u16 ui_data;
|
||||||
|
u8 als_flags;
|
||||||
|
u8 ir_flags;
|
||||||
|
u8 interval;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct iqs62x_event_desc {
|
||||||
|
enum iqs62x_event_reg reg;
|
||||||
|
u8 mask;
|
||||||
|
u8 val;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct iqs62x_dev_desc {
|
||||||
|
const char *dev_name;
|
||||||
|
const struct mfd_cell *sub_devs;
|
||||||
|
int num_sub_devs;
|
||||||
|
|
||||||
|
u8 prod_num;
|
||||||
|
u8 sw_num;
|
||||||
|
const u8 *cal_regs;
|
||||||
|
int num_cal_regs;
|
||||||
|
|
||||||
|
u8 prox_mask;
|
||||||
|
u8 sar_mask;
|
||||||
|
u8 hall_mask;
|
||||||
|
u8 hyst_mask;
|
||||||
|
u8 temp_mask;
|
||||||
|
u8 als_mask;
|
||||||
|
u8 ir_mask;
|
||||||
|
|
||||||
|
u8 prox_settings;
|
||||||
|
u8 als_flags;
|
||||||
|
u8 hall_flags;
|
||||||
|
u8 hyst_shift;
|
||||||
|
|
||||||
|
u8 interval;
|
||||||
|
u8 interval_div;
|
||||||
|
|
||||||
|
u8 clk_div;
|
||||||
|
const char *fw_name;
|
||||||
|
const enum iqs62x_event_reg (*event_regs)[IQS62X_EVENT_SIZE];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct iqs62x_core {
|
||||||
|
const struct iqs62x_dev_desc *dev_desc;
|
||||||
|
struct i2c_client *client;
|
||||||
|
struct regmap *regmap;
|
||||||
|
struct blocking_notifier_head nh;
|
||||||
|
struct list_head fw_blk_head;
|
||||||
|
struct completion fw_done;
|
||||||
|
enum iqs62x_ui_sel ui_sel;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern const struct iqs62x_event_desc iqs62x_events[IQS62X_NUM_EVENTS];
|
||||||
|
|
||||||
|
#endif /* __LINUX_MFD_IQS62X_H */
|
|
@ -620,7 +620,5 @@ struct rk808 {
|
||||||
long variant;
|
long variant;
|
||||||
const struct regmap_config *regmap_cfg;
|
const struct regmap_config *regmap_cfg;
|
||||||
const struct regmap_irq_chip *regmap_irq_chip;
|
const struct regmap_irq_chip *regmap_irq_chip;
|
||||||
void (*pm_pwroff_fn)(void);
|
|
||||||
void (*pm_pwroff_prep_fn)(void);
|
|
||||||
};
|
};
|
||||||
#endif /* __LINUX_REGULATOR_RK808_H */
|
#endif /* __LINUX_REGULATOR_RK808_H */
|
||||||
|
|
|
@ -139,6 +139,17 @@
|
||||||
#define RN5T618_INTPOL 0x9c
|
#define RN5T618_INTPOL 0x9c
|
||||||
#define RN5T618_INTEN 0x9d
|
#define RN5T618_INTEN 0x9d
|
||||||
#define RN5T618_INTMON 0x9e
|
#define RN5T618_INTMON 0x9e
|
||||||
|
|
||||||
|
#define RN5T618_RTC_SECONDS 0xA0
|
||||||
|
#define RN5T618_RTC_MDAY 0xA4
|
||||||
|
#define RN5T618_RTC_MONTH 0xA5
|
||||||
|
#define RN5T618_RTC_YEAR 0xA6
|
||||||
|
#define RN5T618_RTC_ADJUST 0xA7
|
||||||
|
#define RN5T618_RTC_ALARM_Y_SEC 0xA8
|
||||||
|
#define RN5T618_RTC_DAL_MONTH 0xAC
|
||||||
|
#define RN5T618_RTC_CTRL1 0xAE
|
||||||
|
#define RN5T618_RTC_CTRL2 0xAF
|
||||||
|
|
||||||
#define RN5T618_PREVINDAC 0xb0
|
#define RN5T618_PREVINDAC 0xb0
|
||||||
#define RN5T618_BATDAC 0xb1
|
#define RN5T618_BATDAC 0xb1
|
||||||
#define RN5T618_CHGCTL1 0xb3
|
#define RN5T618_CHGCTL1 0xb3
|
||||||
|
@ -242,9 +253,24 @@ enum {
|
||||||
RC5T619,
|
RC5T619,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* RN5T618 IRQ definitions */
|
||||||
|
enum {
|
||||||
|
RN5T618_IRQ_SYS = 0,
|
||||||
|
RN5T618_IRQ_DCDC,
|
||||||
|
RN5T618_IRQ_RTC,
|
||||||
|
RN5T618_IRQ_ADC,
|
||||||
|
RN5T618_IRQ_GPIO,
|
||||||
|
RN5T618_IRQ_CHG,
|
||||||
|
RN5T618_NR_IRQS,
|
||||||
|
};
|
||||||
|
|
||||||
struct rn5t618 {
|
struct rn5t618 {
|
||||||
struct regmap *regmap;
|
struct regmap *regmap;
|
||||||
|
struct device *dev;
|
||||||
long variant;
|
long variant;
|
||||||
|
|
||||||
|
int irq;
|
||||||
|
struct regmap_irq_chip_data *irq_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* __LINUX_MFD_RN5T618_H */
|
#endif /* __LINUX_MFD_RN5T618_H */
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
|
#ifndef __LINUX_MFD_SC27XX_PMIC_H
|
||||||
|
#define __LINUX_MFD_SC27XX_PMIC_H
|
||||||
|
|
||||||
|
extern enum usb_charger_type sprd_pmic_detect_charger_type(struct device *dev);
|
||||||
|
|
||||||
|
#endif /* __LINUX_MFD_SC27XX_PMIC_H */
|
Loading…
Reference in New Issue