Commit 884e0d3d authored by Linus Torvalds's avatar Linus Torvalds

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

Pull MFD updates from Lee Jones:
 "Core Frameworks
   - Make better attempt at matching device with the correct OF node
   - Allow batch removal of hierarchical sub-devices

  New Drivers
   - Add STM32 Clocksource driver
   - Add support for Khadas System Control Microcontroller

  Driver Removal
   - Remove unused driver for TI's SMSC ECE1099

  New Device Support
   - Add support for Intel Emmitsburg PCH to Intel LPSS PCI
   - Add support for Intel Tiger Lake PCH-H to Intel LPSS PCI
   - Add support for Dialog DA revision to Dialog DA9063

  New Functionality
   - Add support for AXP803 to be probed by I2C

  Fix-ups
   - Numerous W=1 warning fixes
   - Device Tree changes (stm32-lptimer, gateworks-gsc, khadas,mcu, stmfx, cros-ec, j721e-system-controller)
   - Enabled Regmap 'fast I/O' in stm32-lptimer
   - Change BUG_ON to WARN_ON in arizona-core
   - Remove superfluous code/initialisation (madera, max14577)
   - Trivial formatting/spelling issues (madera-core, madera-i2c, da9055, max77693-private)
   - Switch to of_platform_populate() in sprd-sc27xx-spi
   - Expand out set/get brightness/pwm macros in lm3533-ctrlbank
   - Disable IRQs on suspend in motorola-cpcap
   - Clean-up error handling in intel_soc_pmic_mrfld
   - Ensure correct removal order of sub-devices in madera
   - Many s/HTTP/HTTPS/ link changes
   - Ensure name used with Regmap is unique in syscon

  Bug Fixes
   - Properly 'put' clock on unbind and error in arizona-core
   - Fix revision handling in da9063
   - Fix 'assignment of read-only location' error in kempld-core
   - Avoid using the Regmap API when atomic in rn5t618
   - Redefine volatile register description in rn5t618
   - Use locking to protect event handler in dln2"

* tag 'mfd-next-5.9-1' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd: (76 commits)
  mfd: syscon: Use a unique name with regmap_config
  mfd: Replace HTTP links with HTTPS ones
  mfd: dln2: Run event handler loop under spinlock
  mfd: madera: Improve handling of regulator unbinding
  mfd: mfd-core: Add mechanism for removal of a subset of children
  mfd: intel_soc_pmic_mrfld: Simplify the return expression of intel_scu_ipc_dev_iowrite8()
  mfd: max14577: Remove redundant initialization of variable current_bits
  mfd: rn5t618: Fix caching of battery related registers
  mfd: max77693-private: Drop a duplicated word
  mfd: da9055: pdata.h: Drop a duplicated word
  mfd: rn5t618: Make restart handler atomic safe
  mfd: kempld-core: Fix 'assignment of read-only location' error
  mfd: axp20x: Allow the AXP803 to be probed by I2C
  mfd: da9063: Add support for latest DA silicon revision
  mfd: da9063: Fix revision handling to correctly select reg tables
  dt-bindings: mfd: st,stmfx: Remove I2C unit name
  dt-bindings: mfd: ti,j721e-system-controller.yaml: Add J721e system controller
  mfd: motorola-cpcap: Disable interrupt for suspend
  mfd: smsc-ece1099: Remove driver
  mfd: core: Add OF_MFD_CELL_REG() helper
  ...
parents 18737f42 e15d7f2b
ChromeOS Embedded Controller
Google's ChromeOS EC is a Cortex-M device which talks to the AP and
implements various function such as keyboard and battery charging.
The EC can be connect through various means (I2C, SPI, LPC, RPMSG) and the
compatible string used depends on the interface. Each connection method has
its own driver which connects to the top level interface-agnostic EC driver.
Other Linux driver (such as cros-ec-keyb for the matrix keyboard) connect to
the top-level driver.
Required properties (I2C):
- compatible: "google,cros-ec-i2c"
- reg: I2C slave address
Required properties (SPI):
- compatible: "google,cros-ec-spi"
- reg: SPI chip select
Required properties (RPMSG):
- compatible: "google,cros-ec-rpmsg"
Optional properties (SPI):
- google,cros-ec-spi-pre-delay: Some implementations of the EC need a little
time to wake up from sleep before they can receive SPI transfers at a high
clock rate. This property specifies the delay, in usecs, between the
assertion of the CS to the start of the first clock pulse.
- google,cros-ec-spi-msg-delay: Some implementations of the EC require some
additional processing time in order to accept new transactions. If the delay
between transactions is not long enough the EC may not be able to respond
properly to subsequent transactions and cause them to hang. This property
specifies the delay, in usecs, introduced between transactions to account
for the time required by the EC to get back into a state in which new data
can be accepted.
Required properties (LPC):
- compatible: "google,cros-ec-lpc"
- reg: List of (IO address, size) pairs defining the interface uses
Optional properties (all):
- google,has-vbc-nvram: Some implementations of the EC include a small
nvram space used to store verified boot context data. This boolean flag
is used to specify whether this nvram is present or not.
Example for I2C:
i2c@12ca0000 {
cros-ec@1e {
reg = <0x1e>;
compatible = "google,cros-ec-i2c";
interrupts = <14 0>;
interrupt-parent = <&wakeup_eint>;
wakeup-source;
};
Example for SPI:
spi@131b0000 {
ec@0 {
compatible = "google,cros-ec-spi";
reg = <0x0>;
interrupts = <14 0>;
interrupt-parent = <&wakeup_eint>;
wakeup-source;
spi-max-frequency = <5000000>;
controller-data {
cs-gpio = <&gpf0 3 4 3 0>;
samsung,spi-cs;
samsung,spi-feedback-delay = <2>;
};
};
};
Example for LPC is not supplied as it is not yet implemented.
...@@ -79,11 +79,12 @@ properties: ...@@ -79,11 +79,12 @@ properties:
description: | description: |
conversion mode: conversion mode:
0 - temperature, in C*10 0 - temperature, in C*10
1 - pre-scaled voltage value 1 - pre-scaled 24-bit voltage value
2 - scaled voltage based on an optional resistor divider 2 - scaled voltage based on an optional resistor divider
and optional offset and optional offset
3 - pre-scaled 16-bit voltage value
$ref: /schemas/types.yaml#/definitions/uint32 $ref: /schemas/types.yaml#/definitions/uint32
enum: [0, 1, 2] enum: [0, 1, 2, 3]
gw,voltage-divider-ohms: gw,voltage-divider-ohms:
description: Values of resistors for divider on raw ADC input description: Values of resistors for divider on raw ADC input
......
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/mfd/google,cros-ec.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: ChromeOS Embedded Controller
maintainers:
- Benson Leung <bleung@chromium.org>
- Enric Balletbo i Serra <enric.balletbo@collabora.com>
- Guenter Roeck <groeck@chromium.org>
description:
Google's ChromeOS EC is a microcontroller which talks to the AP and
implements various functions such as keyboard and battery charging.
The EC can be connected through various interfaces (I2C, SPI, and others)
and the compatible string specifies which interface is being used.
properties:
compatible:
oneOf:
- description:
For implementations of the EC is connected through I2C.
const: google,cros-ec-i2c
- description:
For implementations of the EC is connected through SPI.
const: google,cros-ec-spi
- description:
For implementations of the EC is connected through RPMSG.
const: google,cros-ec-rpmsg
google,cros-ec-spi-pre-delay:
description:
This property specifies the delay in usecs between the
assertion of the CS and the first clock pulse.
allOf:
- $ref: /schemas/types.yaml#/definitions/uint32
- default: 0
- minimum: 0
google,cros-ec-spi-msg-delay:
description:
This property specifies the delay in usecs between messages.
allOf:
- $ref: /schemas/types.yaml#/definitions/uint32
- default: 0
- minimum: 0
google,has-vbc-nvram:
description:
Some implementations of the EC include a small nvram space used to
store verified boot context data. This boolean flag is used to specify
whether this nvram is present or not.
type: boolean
spi-max-frequency:
description: Maximum SPI frequency of the device in Hz.
reg:
maxItems: 1
interrupts:
maxItems: 1
required:
- compatible
if:
properties:
compatible:
contains:
enum:
- google,cros-ec-i2c
- google,cros-ec-rpmsg
then:
properties:
google,cros-ec-spi-pre-delay: false
google,cros-ec-spi-msg-delay: false
spi-max-frequency: false
additionalProperties: false
examples:
# Example for I2C
- |
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
i2c0 {
#address-cells = <1>;
#size-cells = <0>;
cros-ec@1e {
compatible = "google,cros-ec-i2c";
reg = <0x1e>;
interrupts = <6 0>;
interrupt-parent = <&gpio0>;
};
};
# Example for SPI
- |
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
spi0 {
#address-cells = <1>;
#size-cells = <0>;
cros-ec@0 {
compatible = "google,cros-ec-spi";
reg = <0x0>;
google,cros-ec-spi-msg-delay = <30>;
google,cros-ec-spi-pre-delay = <10>;
interrupts = <99 0>;
interrupt-parent = <&gpio7>;
spi-max-frequency = <5000000>;
};
};
# Example for RPMSG
- |
scp0 {
cros-ec {
compatible = "google,cros-ec-rpmsg";
};
};
...
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/mfd/khadas,mcu.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Khadas on-board Microcontroller Device Tree Bindings
maintainers:
- Neil Armstrong <narmstrong@baylibre.com>
description: |
Khadas embeds a microcontroller on their VIM and Edge boards adding some
system feature as PWM Fan control (for VIM2 rev14 or VIM3), User memory
storage, IR/Key resume control, system power LED control and more.
properties:
compatible:
enum:
- khadas,mcu # MCU revision is discoverable
"#cooling-cells": # Only needed for boards having FAN control feature
const: 2
reg:
maxItems: 1
required:
- compatible
- reg
additionalProperties: false
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
khadas_mcu: system-controller@18 {
compatible = "khadas,mcu";
reg = <0x18>;
#cooling-cells = <2>;
};
};
...@@ -33,6 +33,9 @@ properties: ...@@ -33,6 +33,9 @@ properties:
items: items:
- const: mux - const: mux
interrupts:
maxItems: 1
"#address-cells": "#address-cells":
const: 1 const: 1
...@@ -106,11 +109,13 @@ additionalProperties: false ...@@ -106,11 +109,13 @@ additionalProperties: false
examples: examples:
- | - |
#include <dt-bindings/clock/stm32mp1-clks.h> #include <dt-bindings/clock/stm32mp1-clks.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
timer@40002400 { timer@40002400 {
compatible = "st,stm32-lptimer"; compatible = "st,stm32-lptimer";
reg = <0x40002400 0x400>; reg = <0x40002400 0x400>;
clocks = <&timer_clk>; clocks = <&timer_clk>;
clock-names = "mux"; clock-names = "mux";
interrupts-extended = <&exti 47 IRQ_TYPE_LEVEL_HIGH>;
#address-cells = <1>; #address-cells = <1>;
#size-cells = <0>; #size-cells = <0>;
......
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/mfd/st,stmfx.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: STMicroelectonics Multi-Function eXpander (STMFX) bindings
description: ST Multi-Function eXpander (STMFX) is a slave controller using I2C for
communication with the main MCU. Its main features are GPIO expansion,
main MCU IDD measurement (IDD is the amount of current that flows
through VDD) and resistive touchscreen controller.
maintainers:
- Amelie Delaunay <amelie.delaunay@st.com>
properties:
compatible:
const: st,stmfx-0300
reg:
enum: [ 0x42, 0x43 ]
interrupts:
maxItems: 1
drive-open-drain: true
vdd-supply:
maxItems: 1
pinctrl:
type: object
properties:
compatible:
const: st,stmfx-0300-pinctrl
"#gpio-cells":
const: 2
"#interrupt-cells":
const: 2
gpio-controller: true
interrupt-controller: true
gpio-ranges:
description: if all STMFX pins[24:0] are available (no other STMFX function in use),
you should use gpio-ranges = <&stmfx_pinctrl 0 0 24>;
if agpio[3:0] are not available (STMFX Touchscreen function in use),
you should use gpio-ranges = <&stmfx_pinctrl 0 0 16>, <&stmfx_pinctrl 20 20 4>;
if agpio[7:4] are not available (STMFX IDD function in use),
you should use gpio-ranges = <&stmfx_pinctrl 0 0 20>;
maxItems: 1
patternProperties:
"^[a-zA-Z]*-pins$":
type: object
allOf:
- $ref: ../pinctrl/pinmux-node.yaml
properties:
pins: true
bias-disable: true
bias-pull-up: true
bias-pull-pin-default: true
bias-pull-down: true
drive-open-drain: true
drive-push-pull: true
output-high: true
output-low: true
additionalProperties: false
required:
- compatible
- "#gpio-cells"
- "#interrupt-cells"
- gpio-controller
- interrupt-controller
- gpio-ranges
additionalProperties: false
required:
- compatible
- reg
- interrupts
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
stmfx@42 {
compatible = "st,stmfx-0300";
reg = <0x42>;
interrupts = <8 IRQ_TYPE_EDGE_RISING>;
interrupt-parent = <&gpioi>;
vdd-supply = <&v3v3>;
stmfx_pinctrl: pinctrl {
compatible = "st,stmfx-0300-pinctrl";
#gpio-cells = <2>;
#interrupt-cells = <2>;
gpio-controller;
interrupt-controller;
gpio-ranges = <&stmfx_pinctrl 0 0 24>;
joystick_pins: joystick-pins {
pins = "gpio0", "gpio1", "gpio2", "gpio3", "gpio4";
drive-push-pull;
bias-pull-up;
};
};
};
};
...
STMicroelectonics Multi-Function eXpander (STMFX) Core bindings
ST Multi-Function eXpander (STMFX) is a slave controller using I2C for
communication with the main MCU. Its main features are GPIO expansion, main
MCU IDD measurement (IDD is the amount of current that flows through VDD) and
resistive touchscreen controller.
Required properties:
- compatible: should be "st,stmfx-0300".
- reg: I2C slave address of the device.
- interrupts: interrupt specifier triggered by MFX_IRQ_OUT signal.
Please refer to ../interrupt-controller/interrupt.txt
Optional properties:
- drive-open-drain: configure MFX_IRQ_OUT as open drain.
- vdd-supply: phandle of the regulator supplying STMFX.
Example:
stmfx: stmfx@42 {
compatible = "st,stmfx-0300";
reg = <0x42>;
interrupts = <8 IRQ_TYPE_EDGE_RISING>;
interrupt-parent = <&gpioi>;
vdd-supply = <&v3v3>;
};
Please refer to ../pinctrl/pinctrl-stmfx.txt for STMFX GPIO expander function bindings.
...@@ -26,7 +26,7 @@ Optional node: ...@@ -26,7 +26,7 @@ Optional node:
Example: Example:
/* /*
* Integrated Power Management Chip * Integrated Power Management Chip
* http://www.ti.com/lit/ds/symlink/twl6030.pdf * https://www.ti.com/lit/ds/symlink/twl6030.pdf
*/ */
twl@48 { twl@48 {
compatible = "ti,twl6030"; compatible = "ti,twl6030";
......
STMicroelectronics Multi-Function eXpander (STMFX) GPIO expander bindings
ST Multi-Function eXpander (STMFX) offers up to 24 GPIOs expansion.
Please refer to ../mfd/stmfx.txt for STMFX Core bindings.
Required properties:
- compatible: should be "st,stmfx-0300-pinctrl".
- #gpio-cells: should be <2>, the first cell is the GPIO number and the second
cell is the gpio flags in accordance with <dt-bindings/gpio/gpio.h>.
- gpio-controller: marks the device as a GPIO controller.
- #interrupt-cells: should be <2>, the first cell is the GPIO number and the
second cell is the interrupt flags in accordance with
<dt-bindings/interrupt-controller/irq.h>.
- interrupt-controller: marks the device as an interrupt controller.
- gpio-ranges: specifies the mapping between gpio controller and pin
controller pins. Check "Concerning gpio-ranges property" below.
Please refer to ../gpio/gpio.txt.
Please refer to pinctrl-bindings.txt for pin configuration.
Required properties for pin configuration sub-nodes:
- pins: list of pins to which the configuration applies.
Optional properties for pin configuration sub-nodes (pinconf-generic ones):
- bias-disable: disable any bias on the pin.
- bias-pull-up: the pin will be pulled up.
- bias-pull-pin-default: use the pin-default pull state.
- bias-pull-down: the pin will be pulled down.
- drive-open-drain: the pin will be driven with open drain.
- drive-push-pull: the pin will be driven actively high and low.
- output-high: the pin will be configured as an output driving high level.
- output-low: the pin will be configured as an output driving low level.
Note that STMFX pins[15:0] are called "gpio[15:0]", and STMFX pins[23:16] are
called "agpio[7:0]". Example, to refer to pin 18 of STMFX, use "agpio2".
Concerning gpio-ranges property:
- if all STMFX pins[24:0] are available (no other STMFX function in use), you
should use gpio-ranges = <&stmfx_pinctrl 0 0 24>;
- if agpio[3:0] are not available (STMFX Touchscreen function in use), you
should use gpio-ranges = <&stmfx_pinctrl 0 0 16>, <&stmfx_pinctrl 20 20 4>;
- if agpio[7:4] are not available (STMFX IDD function in use), you
should use gpio-ranges = <&stmfx_pinctrl 0 0 20>;
Example:
stmfx: stmfx@42 {
...
stmfx_pinctrl: stmfx-pin-controller {
compatible = "st,stmfx-0300-pinctrl";
#gpio-cells = <2>;
#interrupt-cells = <2>;
gpio-controller;
interrupt-controller;
gpio-ranges = <&stmfx_pinctrl 0 0 24>;
joystick_pins: joystick {
pins = "gpio0", "gpio1", "gpio2", "gpio3", "gpio4";
drive-push-pull;
bias-pull-up;
};
};
};
Example of STMFX GPIO consumers:
joystick {
compatible = "gpio-keys";
#address-cells = <1>;
#size-cells = <0>;
pinctrl-0 = <&joystick_pins>;
pinctrl-names = "default";
button-0 {
label = "JoySel";
linux,code = <KEY_ENTER>;
interrupt-parent = <&stmfx_pinctrl>;
interrupts = <0 IRQ_TYPE_EDGE_RISING>;
};
button-1 {
label = "JoyDown";
linux,code = <KEY_DOWN>;
interrupt-parent = <&stmfx_pinctrl>;
interrupts = <1 IRQ_TYPE_EDGE_RISING>;
};
button-2 {
label = "JoyLeft";
linux,code = <KEY_LEFT>;
interrupt-parent = <&stmfx_pinctrl>;
interrupts = <2 IRQ_TYPE_EDGE_RISING>;
};
button-3 {
label = "JoyRight";
linux,code = <KEY_RIGHT>;
interrupt-parent = <&stmfx_pinctrl>;
interrupts = <3 IRQ_TYPE_EDGE_RISING>;
};
button-4 {
label = "JoyUp";
linux,code = <KEY_UP>;
interrupt-parent = <&stmfx_pinctrl>;
interrupts = <4 IRQ_TYPE_EDGE_RISING>;
};
};
leds {
compatible = "gpio-leds";
orange {
gpios = <&stmfx_pinctrl 17 1>;
};
blue {
gpios = <&stmfx_pinctrl 19 1>;
};
}
...@@ -100,7 +100,6 @@ available subsections can be seen below. ...@@ -100,7 +100,6 @@ available subsections can be seen below.
rfkill rfkill
serial/index serial/index
sm501 sm501
smsc_ece1099
switchtec switchtec
sync_file sync_file
vfio-mediated-device vfio-mediated-device
......
=================================================
Msc Keyboard Scan Expansion/GPIO Expansion device
=================================================
What is smsc-ece1099?
----------------------
The ECE1099 is a 40-Pin 3.3V Keyboard Scan Expansion
or GPIO Expansion device. The device supports a keyboard
scan matrix of 23x8. The device is connected to a Master
via the SMSC BC-Link interface or via the SMBus.
Keypad scan Input(KSI) and Keypad Scan Output(KSO) signals
are multiplexed with GPIOs.
Interrupt generation
--------------------
Interrupts can be generated by an edge detection on a GPIO
pin or an edge detection on one of the bus interface pins.
Interrupts can also be detected on the keyboard scan interface.
The bus interrupt pin (BC_INT# or SMBUS_INT#) is asserted if
any bit in one of the Interrupt Status registers is 1 and
the corresponding Interrupt Mask bit is also 1.
In order for software to determine which device is the source
of an interrupt, it should first read the Group Interrupt Status Register
to determine which Status register group is a source for the interrupt.
Software should read both the Status register and the associated Mask register,
then AND the two values together. Bits that are 1 in the result of the AND
are active interrupts. Software clears an interrupt by writing a 1 to the
corresponding bit in the Status register.
Communication Protocol
----------------------
- SMbus slave Interface
The host processor communicates with the ECE1099 device
through a series of read/write registers via the SMBus
interface. SMBus is a serial communication protocol between
a computer host and its peripheral devices. The SMBus data
rate is 10KHz minimum to 400 KHz maximum
- Slave Bus Interface
The ECE1099 device SMBus implementation is a subset of the
SMBus interface to the host. The device is a slave-only SMBus device.
The implementation in the device is a subset of SMBus since it
only supports four protocols.
The Write Byte, Read Byte, Send Byte, and Receive Byte protocols are the
only valid SMBus protocols for the device.
- BC-LinkTM Interface
The BC-Link is a proprietary bus that allows communication
between a Master device and a Companion device. The Master
device uses this serial bus to read and write registers
located on the Companion device. The bus comprises three signals,
BC_CLK, BC_DAT and BC_INT#. The Master device always provides the
clock, BC_CLK, and the Companion device is the source for an
independent asynchronous interrupt signal, BC_INT#. The ECE1099
supports BC-Link speeds up to 24MHz.
...@@ -9678,6 +9678,15 @@ F: include/linux/kdb.h ...@@ -9678,6 +9678,15 @@ F: include/linux/kdb.h
F: include/linux/kgdb.h F: include/linux/kgdb.h
F: kernel/debug/ F: kernel/debug/
KHADAS MCU MFD DRIVER
M: Neil Armstrong <narmstrong@baylibre.com>
L: linux-amlogic@lists.infradead.org
S: Maintained
F: Documentation/devicetree/bindings/mfd/khadas,mcu.yaml
F: drivers/mfd/khadas-mcu.c
F: include/linux/mfd/khadas-mcu.h
F: drivers/thermal/khadas_mcu_fan.c
KMEMLEAK KMEMLEAK
M: Catalin Marinas <catalin.marinas@arm.com> M: Catalin Marinas <catalin.marinas@arm.com>
S: Maintained S: Maintained
...@@ -14887,6 +14896,13 @@ L: linux-serial@vger.kernel.org ...@@ -14887,6 +14896,13 @@ L: linux-serial@vger.kernel.org
S: Odd Fixes S: Odd Fixes
F: drivers/tty/serial/rp2.* F: drivers/tty/serial/rp2.*
ROHM BD99954 CHARGER IC
R: Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
L: linux-power@fi.rohmeurope.com
S: Supported
F: drivers/power/supply/bd99954-charger.c
F: drivers/power/supply/bd99954-charger.h
ROHM BH1750 AMBIENT LIGHT SENSOR DRIVER ROHM BH1750 AMBIENT LIGHT SENSOR DRIVER
M: Tomasz Duszynski <tduszyns@gmail.com> M: Tomasz Duszynski <tduszyns@gmail.com>
S: Maintained S: Maintained
...@@ -14904,6 +14920,31 @@ F: drivers/mfd/bd9571mwv.c ...@@ -14904,6 +14920,31 @@ F: drivers/mfd/bd9571mwv.c
F: drivers/regulator/bd9571mwv-regulator.c F: drivers/regulator/bd9571mwv-regulator.c
F: include/linux/mfd/bd9571mwv.h F: include/linux/mfd/bd9571mwv.h
ROHM POWER MANAGEMENT IC DEVICE DRIVERS
R: Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
L: linux-power@fi.rohmeurope.com
S: Supported
F: Documentation/devicetree/bindings/mfd/rohm,bd70528-pmic.txt
F: Documentation/devicetree/bindings/regulator/rohm,bd70528-regulator.txt
F: drivers/clk/clk-bd718x7.c
F: drivers/gpio/gpio-bd70528.c
F: drivers/gpio/gpio-bd71828.c
F: drivers/mfd/rohm-bd70528.c
F: drivers/mfd/rohm-bd71828.c
F: drivers/mfd/rohm-bd718x7.c
F: drivers/power/supply/bd70528-charger.c
F: drivers/regulator/bd70528-regulator.c
F: drivers/regulator/bd71828-regulator.c
F: drivers/regulator/bd718x7-regulator.c
F: drivers/regulator/rohm-regulator.c
F: drivers/rtc/rtc-bd70528.c
F: drivers/watchdog/bd70528_wdt.c
F: include/linux/mfd/rohm-bd70528.h
F: include/linux/mfd/rohm-bd71828.h
F: include/linux/mfd/rohm-bd718x7.h
F: include/linux/mfd/rohm-generic.h
F: include/linux/mfd/rohm-shared.h
ROSE NETWORK LAYER ROSE NETWORK LAYER
M: Ralf Baechle <ralf@linux-mips.org> M: Ralf Baechle <ralf@linux-mips.org>
L: linux-hams@vger.kernel.org L: linux-hams@vger.kernel.org
......
...@@ -291,6 +291,10 @@ config CLKSRC_STM32 ...@@ -291,6 +291,10 @@ config CLKSRC_STM32
select CLKSRC_MMIO select CLKSRC_MMIO
select TIMER_OF select TIMER_OF
config CLKSRC_STM32_LP
bool "Low power clocksource for STM32 SoCs"
depends on MFD_STM32_LPTIMER || COMPILE_TEST
config CLKSRC_MPS2 config CLKSRC_MPS2
bool "Clocksource for MPS2 SoCs" if COMPILE_TEST bool "Clocksource for MPS2 SoCs" if COMPILE_TEST
depends on GENERIC_SCHED_CLOCK depends on GENERIC_SCHED_CLOCK
......
...@@ -45,6 +45,7 @@ obj-$(CONFIG_BCM_KONA_TIMER) += bcm_kona_timer.o ...@@ -45,6 +45,7 @@ obj-$(CONFIG_BCM_KONA_TIMER) += bcm_kona_timer.o
obj-$(CONFIG_CADENCE_TTC_TIMER) += timer-cadence-ttc.o obj-$(CONFIG_CADENCE_TTC_TIMER) += timer-cadence-ttc.o
obj-$(CONFIG_CLKSRC_EFM32) += timer-efm32.o obj-$(CONFIG_CLKSRC_EFM32) += timer-efm32.o
obj-$(CONFIG_CLKSRC_STM32) += timer-stm32.o obj-$(CONFIG_CLKSRC_STM32) += timer-stm32.o
obj-$(CONFIG_CLKSRC_STM32_LP) += timer-stm32-lp.o
obj-$(CONFIG_CLKSRC_EXYNOS_MCT) += exynos_mct.o obj-$(CONFIG_CLKSRC_EXYNOS_MCT) += exynos_mct.o
obj-$(CONFIG_CLKSRC_LPC32XX) += timer-lpc32xx.o obj-$(CONFIG_CLKSRC_LPC32XX) += timer-lpc32xx.o
obj-$(CONFIG_CLKSRC_MPS2) += mps2-timer.o obj-$(CONFIG_CLKSRC_MPS2) += mps2-timer.o
......
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) STMicroelectronics 2019 - All Rights Reserved
* Authors: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics.
* Pascal Paillet <p.paillet@st.com> for STMicroelectronics.
*/
#include <linux/clk.h>
#include <linux/clockchips.h>
#include <linux/interrupt.h>
#include <linux/mfd/stm32-lptimer.h>
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/platform_device.h>
#include <linux/pm_wakeirq.h>
#define CFGR_PSC_OFFSET 9
#define STM32_LP_RATING 1000
#define STM32_TARGET_CLKRATE (32000 * HZ)
#define STM32_LP_MAX_PSC 7
struct stm32_lp_private {
struct regmap *reg;
struct clock_event_device clkevt;
unsigned long period;
struct device *dev;
};
static struct stm32_lp_private*
to_priv(struct clock_event_device *clkevt)
{
return container_of(clkevt, struct stm32_lp_private, clkevt);
}
static int stm32_clkevent_lp_shutdown(struct clock_event_device *clkevt)
{
struct stm32_lp_private *priv = to_priv(clkevt);
regmap_write(priv->reg, STM32_LPTIM_CR, 0);
regmap_write(priv->reg, STM32_LPTIM_IER, 0);
/* clear pending flags */
regmap_write(priv->reg, STM32_LPTIM_ICR, STM32_LPTIM_ARRMCF);
return 0;
}
static int stm32_clkevent_lp_set_timer(unsigned long evt,
struct clock_event_device *clkevt,
int is_periodic)
{
struct stm32_lp_private *priv = to_priv(clkevt);
/* disable LPTIMER to be able to write into IER register*/
regmap_write(priv->reg, STM32_LPTIM_CR, 0);
/* enable ARR interrupt */
regmap_write(priv->reg, STM32_LPTIM_IER, STM32_LPTIM_ARRMIE);
/* enable LPTIMER to be able to write into ARR register */
regmap_write(priv->reg, STM32_LPTIM_CR, STM32_LPTIM_ENABLE);
/* set next event counter */
regmap_write(priv->reg, STM32_LPTIM_ARR, evt);
/* start counter */
if (is_periodic)
regmap_write(priv->reg, STM32_LPTIM_CR,
STM32_LPTIM_CNTSTRT | STM32_LPTIM_ENABLE);
else
regmap_write(priv->reg, STM32_LPTIM_CR,
STM32_LPTIM_SNGSTRT | STM32_LPTIM_ENABLE);
return 0;
}
static int stm32_clkevent_lp_set_next_event(unsigned long evt,
struct clock_event_device *clkevt)
{
return stm32_clkevent_lp_set_timer(evt, clkevt,
clockevent_state_periodic(clkevt));
}
static int stm32_clkevent_lp_set_periodic(struct clock_event_device *clkevt)
{
struct stm32_lp_private *priv = to_priv(clkevt);
return stm32_clkevent_lp_set_timer(priv->period, clkevt, true);
}
static int stm32_clkevent_lp_set_oneshot(struct clock_event_device *clkevt)
{
struct stm32_lp_private *priv = to_priv(clkevt);
return stm32_clkevent_lp_set_timer(priv->period, clkevt, false);
}
static irqreturn_t stm32_clkevent_lp_irq_handler(int irq, void *dev_id)
{
struct clock_event_device *clkevt = (struct clock_event_device *)dev_id;
struct stm32_lp_private *priv = to_priv(clkevt);
regmap_write(priv->reg, STM32_LPTIM_ICR, STM32_LPTIM_ARRMCF);
if (clkevt->event_handler)
clkevt->event_handler(clkevt);
return IRQ_HANDLED;
}
static void stm32_clkevent_lp_set_prescaler(struct stm32_lp_private *priv,
unsigned long *rate)
{
int i;
for (i = 0; i <= STM32_LP_MAX_PSC; i++) {
if (DIV_ROUND_CLOSEST(*rate, 1 << i) < STM32_TARGET_CLKRATE)
break;
}
regmap_write(priv->reg, STM32_LPTIM_CFGR, i << CFGR_PSC_OFFSET);
/* Adjust rate and period given the prescaler value */
*rate = DIV_ROUND_CLOSEST(*rate, (1 << i));
priv->period = DIV_ROUND_UP(*rate, HZ);
}
static void stm32_clkevent_lp_init(struct stm32_lp_private *priv,
struct device_node *np, unsigned long rate)
{
priv->clkevt.name = np->full_name;
priv->clkevt.cpumask = cpu_possible_mask;
priv->clkevt.features = CLOCK_EVT_FEAT_PERIODIC |
CLOCK_EVT_FEAT_ONESHOT;
priv->clkevt.set_state_shutdown = stm32_clkevent_lp_shutdown;
priv->clkevt.set_state_periodic = stm32_clkevent_lp_set_periodic;
priv->clkevt.set_state_oneshot = stm32_clkevent_lp_set_oneshot;
priv->clkevt.set_next_event = stm32_clkevent_lp_set_next_event;
priv->clkevt.rating = STM32_LP_RATING;
clockevents_config_and_register(&priv->clkevt, rate, 0x1,
STM32_LPTIM_MAX_ARR);
}
static int stm32_clkevent_lp_probe(struct platform_device *pdev)
{
struct stm32_lptimer *ddata = dev_get_drvdata(pdev->dev.parent);
struct stm32_lp_private *priv;
unsigned long rate;
int ret, irq;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->reg = ddata->regmap;
ret = clk_prepare_enable(ddata->clk);
if (ret)
return -EINVAL;
rate = clk_get_rate(ddata->clk);
if (!rate) {
ret = -EINVAL;
goto out_clk_disable;
}
irq = platform_get_irq(to_platform_device(pdev->dev.parent), 0);
if (irq <= 0) {
ret = irq;
goto out_clk_disable;
}
if (of_property_read_bool(pdev->dev.parent->of_node, "wakeup-source")) {
ret = device_init_wakeup(&pdev->dev, true);
if (ret)
goto out_clk_disable;
ret = dev_pm_set_wake_irq(&pdev->dev, irq);
if (ret)
goto out_clk_disable;
}
ret = devm_request_irq(&pdev->dev, irq, stm32_clkevent_lp_irq_handler,
IRQF_TIMER, pdev->name, &priv->clkevt);
if (ret)
goto out_clk_disable;
stm32_clkevent_lp_set_prescaler(priv, &rate);
stm32_clkevent_lp_init(priv, pdev->dev.parent->of_node, rate);
priv->dev = &pdev->dev;
return 0;
out_clk_disable:
clk_disable_unprepare(ddata->clk);
return ret;
}
static int stm32_clkevent_lp_remove(struct platform_device *pdev)
{
return -EBUSY; /* cannot unregister clockevent */
}
static const struct of_device_id stm32_clkevent_lp_of_match[] = {
{ .compatible = "st,stm32-lptimer-timer", },
{},
};
MODULE_DEVICE_TABLE(of, stm32_clkevent_lp_of_match);
static struct platform_driver stm32_clkevent_lp_driver = {
.probe = stm32_clkevent_lp_probe,
.remove = stm32_clkevent_lp_remove,
.driver = {
.name = "stm32-lptimer-timer",
.of_match_table = of_match_ptr(stm32_clkevent_lp_of_match),
},
};
module_platform_driver(stm32_clkevent_lp_driver);
MODULE_ALIAS("platform:stm32-lptimer-timer");
MODULE_DESCRIPTION("STMicroelectronics STM32 clockevent low power driver");
MODULE_LICENSE("GPL v2");
...@@ -1193,18 +1193,6 @@ config MFD_SKY81452 ...@@ -1193,18 +1193,6 @@ config MFD_SKY81452
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 sky81452. will be called sky81452.
config MFD_SMSC
bool "SMSC ECE1099 series chips"
depends on I2C=y
select MFD_CORE
select REGMAP_I2C
help
If you say yes here you get support for the
ece1099 chips from SMSC.
To compile this driver as a module, choose M here: the
module will be called smsc.
config MFD_SC27XX_PMIC config MFD_SC27XX_PMIC
tristate "Spreadtrum SC27xx PMICs" tristate "Spreadtrum SC27xx PMICs"
depends on ARCH_SPRD || COMPILE_TEST depends on ARCH_SPRD || COMPILE_TEST
...@@ -2053,6 +2041,27 @@ config MFD_WCD934X ...@@ -2053,6 +2041,27 @@ config MFD_WCD934X
This driver provides common support WCD934x audio codec and its This driver provides common support WCD934x audio codec and its
associated Pin Controller, Soundwire Controller and Audio codec. associated Pin Controller, Soundwire Controller and Audio codec.
config MFD_KHADAS_MCU
tristate "Support for Khadas System control Microcontroller"
depends on I2C
depends on ARCH_MESON || ARCH_ROCKCHIP || COMPILE_TEST
select MFD_CORE
select REGMAP_I2C
help
Support for the Khadas System control Microcontroller interface
present on their VIM and Edge boards.
This Microcontroller is present on the Khadas VIM1, VIM2, VIM3 and
Edge boards.
It provides multiple boot control features like password check,
power-on options, power-off control and system FAN control on recent
boards.
This driver provides common support for accessing the device,
additional drivers must be enabled in order to use the functionality
of the device.
menu "Multimedia Capabilities Port drivers" menu "Multimedia Capabilities Port drivers"
depends on ARCH_SA1100 depends on ARCH_SA1100
......
...@@ -127,7 +127,6 @@ obj-$(CONFIG_MFD_CPCAP) += motorola-cpcap.o ...@@ -127,7 +127,6 @@ obj-$(CONFIG_MFD_CPCAP) += motorola-cpcap.o
obj-$(CONFIG_MCP) += mcp-core.o obj-$(CONFIG_MCP) += mcp-core.o
obj-$(CONFIG_MCP_SA11X0) += mcp-sa11x0.o obj-$(CONFIG_MCP_SA11X0) += mcp-sa11x0.o
obj-$(CONFIG_MCP_UCB1200) += ucb1x00-core.o obj-$(CONFIG_MCP_UCB1200) += ucb1x00-core.o
obj-$(CONFIG_MFD_SMSC) += smsc-ece1099.o
obj-$(CONFIG_MCP_UCB1200_TS) += ucb1x00-ts.o obj-$(CONFIG_MCP_UCB1200_TS) += ucb1x00-ts.o
ifeq ($(CONFIG_SA1100_ASSABET),y) ifeq ($(CONFIG_SA1100_ASSABET),y)
...@@ -262,5 +261,6 @@ obj-$(CONFIG_MFD_ROHM_BD70528) += rohm-bd70528.o ...@@ -262,5 +261,6 @@ obj-$(CONFIG_MFD_ROHM_BD70528) += rohm-bd70528.o
obj-$(CONFIG_MFD_ROHM_BD71828) += rohm-bd71828.o obj-$(CONFIG_MFD_ROHM_BD71828) += rohm-bd71828.o
obj-$(CONFIG_MFD_ROHM_BD718XX) += rohm-bd718x7.o obj-$(CONFIG_MFD_ROHM_BD718XX) += rohm-bd718x7.o
obj-$(CONFIG_MFD_STMFX) += stmfx.o obj-$(CONFIG_MFD_STMFX) += stmfx.o
obj-$(CONFIG_MFD_KHADAS_MCU) += khadas-mcu.o
obj-$(CONFIG_SGI_MFD_IOC3) += ioc3.o obj-$(CONFIG_SGI_MFD_IOC3) += ioc3.o
...@@ -498,7 +498,7 @@ static ssize_t ab3100_get_set_reg(struct file *file, ...@@ -498,7 +498,7 @@ static ssize_t ab3100_get_set_reg(struct file *file,
int i = 0; int i = 0;
/* Get userspace string and assure termination */ /* Get userspace string and assure termination */
buf_size = min(count, (sizeof(buf)-1)); buf_size = min((ssize_t)count, (ssize_t)(sizeof(buf)-1));
if (copy_from_user(buf, user_buf, buf_size)) if (copy_from_user(buf, user_buf, buf_size))
return -EFAULT; return -EFAULT;
buf[buf_size] = 0; buf[buf_size] = 0;
......
...@@ -29,22 +29,22 @@ ...@@ -29,22 +29,22 @@
/** /**
* struct ab3100_otp * struct ab3100_otp
* @dev containing device * @dev: containing device
* @locked whether the OTP is locked, after locking, no more bits * @locked: whether the OTP is locked, after locking, no more bits
* can be changed but before locking it is still possible * can be changed but before locking it is still possible
* to change bits from 1->0. * to change bits from 1->0.
* @freq clocking frequency for the OTP, this frequency is either * @freq: clocking frequency for the OTP, this frequency is either
* 32768Hz or 1MHz/30 * 32768Hz or 1MHz/30
* @paf product activation flag, indicates whether this is a real * @paf: product activation flag, indicates whether this is a real
* product (paf true) or a lab board etc (paf false) * product (paf true) or a lab board etc (paf false)
* @imeich if this is set it is possible to override the * @imeich: if this is set it is possible to override the
* IMEI number found in the tac, fac and svn fields with * IMEI number found in the tac, fac and svn fields with
* (secured) software * (secured) software
* @cid customer ID * @cid: customer ID
* @tac type allocation code of the IMEI * @tac: type allocation code of the IMEI
* @fac final assembly code of the IMEI * @fac: final assembly code of the IMEI
* @svn software version number of the IMEI * @svn: software version number of the IMEI
* @debugfs a debugfs file used when dumping to file * @debugfs: a debugfs file used when dumping to file
*/ */
struct ab3100_otp { struct ab3100_otp {
struct device *dev; struct device *dev;
......
...@@ -1801,7 +1801,7 @@ static ssize_t ab8500_hwreg_write(struct file *file, ...@@ -1801,7 +1801,7 @@ static ssize_t ab8500_hwreg_write(struct file *file,
int buf_size, ret; int buf_size, ret;
/* Get userspace string and assure termination */ /* Get userspace string and assure termination */
buf_size = min(count, (sizeof(buf)-1)); buf_size = min((int)count, (int)(sizeof(buf)-1));
if (copy_from_user(buf, user_buf, buf_size)) if (copy_from_user(buf, user_buf, buf_size))
return -EFAULT; return -EFAULT;
buf[buf_size] = 0; buf[buf_size] = 0;
......
...@@ -22,11 +22,9 @@ ...@@ -22,11 +22,9 @@
/** /**
* struct altr_sysmgr - Altera SOCFPGA System Manager * struct altr_sysmgr - Altera SOCFPGA System Manager
* @regmap: the regmap used for System Manager accesses. * @regmap: the regmap used for System Manager accesses.
* @base : the base address for the System Manager
*/ */
struct altr_sysmgr { struct altr_sysmgr {
struct regmap *regmap; struct regmap *regmap;
resource_size_t *base;
}; };
static struct platform_driver altr_sysmgr_driver; static struct platform_driver altr_sysmgr_driver;
...@@ -91,6 +89,9 @@ static struct regmap_config altr_sysmgr_regmap_cfg = { ...@@ -91,6 +89,9 @@ static struct regmap_config altr_sysmgr_regmap_cfg = {
* altr_sysmgr_regmap_lookup_by_phandle * altr_sysmgr_regmap_lookup_by_phandle
* Find the sysmgr previous configured in probe() and return regmap property. * Find the sysmgr previous configured in probe() and return regmap property.
* Return: regmap if found or error if not found. * Return: regmap if found or error if not found.
*
* @np: Pointer to device's Device Tree node
* @property: Device Tree property name which references the sysmgr
*/ */
struct regmap *altr_sysmgr_regmap_lookup_by_phandle(struct device_node *np, struct regmap *altr_sysmgr_regmap_lookup_by_phandle(struct device_node *np,
const char *property) const char *property)
...@@ -127,6 +128,7 @@ static int sysmgr_probe(struct platform_device *pdev) ...@@ -127,6 +128,7 @@ static int sysmgr_probe(struct platform_device *pdev)
struct regmap_config sysmgr_config = altr_sysmgr_regmap_cfg; struct regmap_config sysmgr_config = altr_sysmgr_regmap_cfg;
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node; struct device_node *np = dev->of_node;
void __iomem *base;
sysmgr = devm_kzalloc(dev, sizeof(*sysmgr), GFP_KERNEL); sysmgr = devm_kzalloc(dev, sizeof(*sysmgr), GFP_KERNEL);
if (!sysmgr) if (!sysmgr)
...@@ -139,22 +141,19 @@ static int sysmgr_probe(struct platform_device *pdev) ...@@ -139,22 +141,19 @@ static int sysmgr_probe(struct platform_device *pdev)
sysmgr_config.max_register = resource_size(res) - sysmgr_config.max_register = resource_size(res) -
sysmgr_config.reg_stride; sysmgr_config.reg_stride;
if (of_device_is_compatible(np, "altr,sys-mgr-s10")) { if (of_device_is_compatible(np, "altr,sys-mgr-s10")) {
/* Need physical address for SMCC call */
sysmgr->base = (resource_size_t *)res->start;
sysmgr_config.reg_read = s10_protected_reg_read; sysmgr_config.reg_read = s10_protected_reg_read;
sysmgr_config.reg_write = s10_protected_reg_write; sysmgr_config.reg_write = s10_protected_reg_write;
regmap = devm_regmap_init(dev, NULL, sysmgr->base, /* Need physical address for SMCC call */
regmap = devm_regmap_init(dev, NULL, (void *)res->start,
&sysmgr_config); &sysmgr_config);
} else { } else {
sysmgr->base = devm_ioremap(dev, res->start, base = devm_ioremap(dev, res->start, resource_size(res));
resource_size(res)); if (!base)
if (!sysmgr->base)
return -ENOMEM; return -ENOMEM;
sysmgr_config.max_register = res->end - res->start - 3; sysmgr_config.max_register = res->end - res->start - 3;
regmap = devm_regmap_init_mmio(dev, sysmgr->base, regmap = devm_regmap_init_mmio(dev, base, &sysmgr_config);
&sysmgr_config);
} }
if (IS_ERR(regmap)) { if (IS_ERR(regmap)) {
......
...@@ -80,7 +80,7 @@ int arizona_clk32k_disable(struct arizona *arizona) ...@@ -80,7 +80,7 @@ int arizona_clk32k_disable(struct arizona *arizona)
{ {
mutex_lock(&arizona->clk_lock); mutex_lock(&arizona->clk_lock);
BUG_ON(arizona->clk32k_ref <= 0); WARN_ON(arizona->clk32k_ref <= 0);
arizona->clk32k_ref--; arizona->clk32k_ref--;
...@@ -1426,6 +1426,15 @@ int arizona_dev_init(struct arizona *arizona) ...@@ -1426,6 +1426,15 @@ int arizona_dev_init(struct arizona *arizona)
arizona_irq_exit(arizona); arizona_irq_exit(arizona);
err_pm: err_pm:
pm_runtime_disable(arizona->dev); pm_runtime_disable(arizona->dev);
switch (arizona->pdata.clk32k_src) {
case ARIZONA_32KZ_MCLK1:
case ARIZONA_32KZ_MCLK2:
arizona_clk32k_disable(arizona);
break;
default:
break;
}
err_reset: err_reset:
arizona_enable_reset(arizona); arizona_enable_reset(arizona);
regulator_disable(arizona->dcvdd); regulator_disable(arizona->dcvdd);
...@@ -1448,6 +1457,15 @@ int arizona_dev_exit(struct arizona *arizona) ...@@ -1448,6 +1457,15 @@ int arizona_dev_exit(struct arizona *arizona)
regulator_disable(arizona->dcvdd); regulator_disable(arizona->dcvdd);
regulator_put(arizona->dcvdd); regulator_put(arizona->dcvdd);
switch (arizona->pdata.clk32k_src) {
case ARIZONA_32KZ_MCLK1:
case ARIZONA_32KZ_MCLK2:
arizona_clk32k_disable(arizona);
break;
default:
break;
}
mfd_remove_devices(arizona->dev); mfd_remove_devices(arizona->dev);
arizona_free_irq(arizona, ARIZONA_IRQ_UNDERCLOCKED, arizona); arizona_free_irq(arizona, ARIZONA_IRQ_UNDERCLOCKED, arizona);
arizona_free_irq(arizona, ARIZONA_IRQ_OVERCLOCKED, arizona); arizona_free_irq(arizona, ARIZONA_IRQ_OVERCLOCKED, arizona);
......
...@@ -237,7 +237,7 @@ EXPORT_SYMBOL_GPL(atmel_smc_cs_conf_set_cycle); ...@@ -237,7 +237,7 @@ EXPORT_SYMBOL_GPL(atmel_smc_cs_conf_set_cycle);
* atmel_smc_cs_conf_apply - apply an SMC CS conf * atmel_smc_cs_conf_apply - apply an SMC CS conf
* @regmap: the SMC regmap * @regmap: the SMC regmap
* @cs: the CS id * @cs: the CS id
* @conf the SMC CS conf to apply * @conf: the SMC CS conf to apply
* *
* Applies an SMC CS configuration. * Applies an SMC CS configuration.
* Only valid on at91sam9/avr32 SoCs. * Only valid on at91sam9/avr32 SoCs.
...@@ -257,7 +257,7 @@ EXPORT_SYMBOL_GPL(atmel_smc_cs_conf_apply); ...@@ -257,7 +257,7 @@ EXPORT_SYMBOL_GPL(atmel_smc_cs_conf_apply);
* @regmap: the HSMC regmap * @regmap: the HSMC regmap
* @cs: the CS id * @cs: the CS id
* @layout: the layout of registers * @layout: the layout of registers
* @conf the SMC CS conf to apply * @conf: the SMC CS conf to apply
* *
* Applies an SMC CS configuration. * Applies an SMC CS configuration.
* Only valid on post-sama5 SoCs. * Only valid on post-sama5 SoCs.
......
...@@ -63,6 +63,7 @@ static const struct of_device_id axp20x_i2c_of_match[] = { ...@@ -63,6 +63,7 @@ static const struct of_device_id axp20x_i2c_of_match[] = {
{ .compatible = "x-powers,axp209", .data = (void *)AXP209_ID }, { .compatible = "x-powers,axp209", .data = (void *)AXP209_ID },
{ .compatible = "x-powers,axp221", .data = (void *)AXP221_ID }, { .compatible = "x-powers,axp221", .data = (void *)AXP221_ID },
{ .compatible = "x-powers,axp223", .data = (void *)AXP223_ID }, { .compatible = "x-powers,axp223", .data = (void *)AXP223_ID },
{ .compatible = "x-powers,axp803", .data = (void *)AXP803_ID },
{ .compatible = "x-powers,axp806", .data = (void *)AXP806_ID }, { .compatible = "x-powers,axp806", .data = (void *)AXP806_ID },
{ }, { },
}; };
...@@ -74,11 +75,13 @@ static const struct i2c_device_id axp20x_i2c_id[] = { ...@@ -74,11 +75,13 @@ static const struct i2c_device_id axp20x_i2c_id[] = {
{ "axp209", 0 }, { "axp209", 0 },
{ "axp221", 0 }, { "axp221", 0 },
{ "axp223", 0 }, { "axp223", 0 },
{ "axp803", 0 },
{ "axp806", 0 }, { "axp806", 0 },
{ }, { },
}; };
MODULE_DEVICE_TABLE(i2c, axp20x_i2c_id); MODULE_DEVICE_TABLE(i2c, axp20x_i2c_id);
#ifdef CONFIG_ACPI
static const struct acpi_device_id axp20x_i2c_acpi_match[] = { static const struct acpi_device_id axp20x_i2c_acpi_match[] = {
{ {
.id = "INT33F4", .id = "INT33F4",
...@@ -87,6 +90,7 @@ static const struct acpi_device_id axp20x_i2c_acpi_match[] = { ...@@ -87,6 +90,7 @@ static const struct acpi_device_id axp20x_i2c_acpi_match[] = {
{ }, { },
}; };
MODULE_DEVICE_TABLE(acpi, axp20x_i2c_acpi_match); MODULE_DEVICE_TABLE(acpi, axp20x_i2c_acpi_match);
#endif
static struct i2c_driver axp20x_i2c_driver = { static struct i2c_driver axp20x_i2c_driver = {
.driver = { .driver = {
......
...@@ -24,7 +24,7 @@ static struct class cros_class = { ...@@ -24,7 +24,7 @@ static struct class cros_class = {
}; };
/** /**
* cros_feature_to_name - CrOS feature id to name/short description. * struct cros_feature_to_name - CrOS feature id to name/short description.
* @id: The feature identifier. * @id: The feature identifier.
* @name: Device name associated with the feature id. * @name: Device name associated with the feature id.
* @desc: Short name that will be displayed. * @desc: Short name that will be displayed.
...@@ -36,7 +36,7 @@ struct cros_feature_to_name { ...@@ -36,7 +36,7 @@ struct cros_feature_to_name {
}; };
/** /**
* cros_feature_to_cells - CrOS feature id to mfd cells association. * struct cros_feature_to_cells - CrOS feature id to mfd cells association.
* @id: The feature identifier. * @id: The feature identifier.
* @mfd_cells: Pointer to the array of mfd cells that needs to be added. * @mfd_cells: Pointer to the array of mfd cells that needs to be added.
* @num_cells: Number of mfd cells into the array. * @num_cells: Number of mfd cells into the array.
......
...@@ -160,7 +160,6 @@ static int da9063_clear_fault_log(struct da9063 *da9063) ...@@ -160,7 +160,6 @@ static int da9063_clear_fault_log(struct da9063 *da9063)
int da9063_device_init(struct da9063 *da9063, unsigned int irq) int da9063_device_init(struct da9063 *da9063, unsigned int irq)
{ {
int model, variant_id, variant_code;
int ret; int ret;
ret = da9063_clear_fault_log(da9063); ret = da9063_clear_fault_log(da9063);
...@@ -171,36 +170,6 @@ int da9063_device_init(struct da9063 *da9063, unsigned int irq) ...@@ -171,36 +170,6 @@ int da9063_device_init(struct da9063 *da9063, unsigned int irq)
da9063->irq_base = -1; da9063->irq_base = -1;
da9063->chip_irq = irq; da9063->chip_irq = irq;
ret = regmap_read(da9063->regmap, DA9063_REG_CHIP_ID, &model);
if (ret < 0) {
dev_err(da9063->dev, "Cannot read chip model id.\n");
return -EIO;
}
if (model != PMIC_CHIP_ID_DA9063) {
dev_err(da9063->dev, "Invalid chip model id: 0x%02x\n", model);
return -ENODEV;
}
ret = regmap_read(da9063->regmap, DA9063_REG_CHIP_VARIANT, &variant_id);
if (ret < 0) {
dev_err(da9063->dev, "Cannot read chip variant id.\n");
return -EIO;
}
variant_code = variant_id >> DA9063_CHIP_VARIANT_SHIFT;
dev_info(da9063->dev,
"Device detected (chip-ID: 0x%02X, var-ID: 0x%02X)\n",
model, variant_id);
if (variant_code < PMIC_DA9063_BB && variant_code != PMIC_DA9063_AD) {
dev_err(da9063->dev,
"Cannot support variant code: 0x%02X\n", variant_code);
return -ENODEV;
}
da9063->variant_code = variant_code;
ret = da9063_irq_init(da9063); ret = da9063_irq_init(da9063);
if (ret) { if (ret) {
dev_err(da9063->dev, "Cannot initialize interrupts.\n"); dev_err(da9063->dev, "Cannot initialize interrupts.\n");
......
...@@ -22,12 +22,124 @@ ...@@ -22,12 +22,124 @@
#include <linux/of.h> #include <linux/of.h>
#include <linux/regulator/of_regulator.h> #include <linux/regulator/of_regulator.h>
/*
* Raw I2C access required for just accessing chip and variant info before we
* know which device is present. The info read from the device using this
* approach is then used to select the correct regmap tables.
*/
#define DA9063_REG_PAGE_SIZE 0x100
#define DA9063_REG_PAGED_ADDR_MASK 0xFF
enum da9063_page_sel_buf_fmt {
DA9063_PAGE_SEL_BUF_PAGE_REG = 0,
DA9063_PAGE_SEL_BUF_PAGE_VAL,
DA9063_PAGE_SEL_BUF_SIZE,
};
enum da9063_paged_read_msgs {
DA9063_PAGED_READ_MSG_PAGE_SEL = 0,
DA9063_PAGED_READ_MSG_REG_SEL,
DA9063_PAGED_READ_MSG_DATA,
DA9063_PAGED_READ_MSG_CNT,
};
static int da9063_i2c_blockreg_read(struct i2c_client *client, u16 addr,
u8 *buf, int count)
{
struct i2c_msg xfer[DA9063_PAGED_READ_MSG_CNT];
u8 page_sel_buf[DA9063_PAGE_SEL_BUF_SIZE];
u8 page_num, paged_addr;
int ret;
/* Determine page info based on register address */
page_num = (addr / DA9063_REG_PAGE_SIZE);
if (page_num > 1) {
dev_err(&client->dev, "Invalid register address provided\n");
return -EINVAL;
}
paged_addr = (addr % DA9063_REG_PAGE_SIZE) & DA9063_REG_PAGED_ADDR_MASK;
page_sel_buf[DA9063_PAGE_SEL_BUF_PAGE_REG] = DA9063_REG_PAGE_CON;
page_sel_buf[DA9063_PAGE_SEL_BUF_PAGE_VAL] =
(page_num << DA9063_I2C_PAGE_SEL_SHIFT) & DA9063_REG_PAGE_MASK;
/* Write reg address, page selection */
xfer[DA9063_PAGED_READ_MSG_PAGE_SEL].addr = client->addr;
xfer[DA9063_PAGED_READ_MSG_PAGE_SEL].flags = 0;
xfer[DA9063_PAGED_READ_MSG_PAGE_SEL].len = DA9063_PAGE_SEL_BUF_SIZE;
xfer[DA9063_PAGED_READ_MSG_PAGE_SEL].buf = page_sel_buf;
/* Select register address */
xfer[DA9063_PAGED_READ_MSG_REG_SEL].addr = client->addr;
xfer[DA9063_PAGED_READ_MSG_REG_SEL].flags = 0;
xfer[DA9063_PAGED_READ_MSG_REG_SEL].len = sizeof(paged_addr);
xfer[DA9063_PAGED_READ_MSG_REG_SEL].buf = &paged_addr;
/* Read data */
xfer[DA9063_PAGED_READ_MSG_DATA].addr = client->addr;
xfer[DA9063_PAGED_READ_MSG_DATA].flags = I2C_M_RD;
xfer[DA9063_PAGED_READ_MSG_DATA].len = count;
xfer[DA9063_PAGED_READ_MSG_DATA].buf = buf;
ret = i2c_transfer(client->adapter, xfer, DA9063_PAGED_READ_MSG_CNT);
if (ret < 0) {
dev_err(&client->dev, "Paged block read failed: %d\n", ret);
return ret;
}
if (ret != DA9063_PAGED_READ_MSG_CNT) {
dev_err(&client->dev, "Paged block read failed to complete\n");
return -EIO;
}
return 0;
}
enum {
DA9063_DEV_ID_REG = 0,
DA9063_VAR_ID_REG,
DA9063_CHIP_ID_REGS,
};
static int da9063_get_device_type(struct i2c_client *i2c, struct da9063 *da9063)
{
u8 buf[DA9063_CHIP_ID_REGS];
int ret;
ret = da9063_i2c_blockreg_read(i2c, DA9063_REG_DEVICE_ID, buf,
DA9063_CHIP_ID_REGS);
if (ret)
return ret;
if (buf[DA9063_DEV_ID_REG] != PMIC_CHIP_ID_DA9063) {
dev_err(da9063->dev,
"Invalid chip device ID: 0x%02x\n",
buf[DA9063_DEV_ID_REG]);
return -ENODEV;
}
dev_info(da9063->dev,
"Device detected (chip-ID: 0x%02X, var-ID: 0x%02X)\n",
buf[DA9063_DEV_ID_REG], buf[DA9063_VAR_ID_REG]);
da9063->variant_code =
(buf[DA9063_VAR_ID_REG] & DA9063_VARIANT_ID_MRC_MASK)
>> DA9063_VARIANT_ID_MRC_SHIFT;
return 0;
}
/*
* Variant specific regmap configs
*/
static const struct regmap_range da9063_ad_readable_ranges[] = { static const struct regmap_range da9063_ad_readable_ranges[] = {
regmap_reg_range(DA9063_REG_PAGE_CON, DA9063_AD_REG_SECOND_D), regmap_reg_range(DA9063_REG_PAGE_CON, DA9063_AD_REG_SECOND_D),
regmap_reg_range(DA9063_REG_SEQ, DA9063_REG_ID_32_31), regmap_reg_range(DA9063_REG_SEQ, DA9063_REG_ID_32_31),
regmap_reg_range(DA9063_REG_SEQ_A, DA9063_REG_AUTO3_LOW), regmap_reg_range(DA9063_REG_SEQ_A, DA9063_REG_AUTO3_LOW),
regmap_reg_range(DA9063_REG_T_OFFSET, DA9063_AD_REG_GP_ID_19), regmap_reg_range(DA9063_REG_T_OFFSET, DA9063_AD_REG_GP_ID_19),
regmap_reg_range(DA9063_REG_CHIP_ID, DA9063_REG_CHIP_VARIANT), regmap_reg_range(DA9063_REG_DEVICE_ID, DA9063_REG_VARIANT_ID),
}; };
static const struct regmap_range da9063_ad_writeable_ranges[] = { static const struct regmap_range da9063_ad_writeable_ranges[] = {
...@@ -72,7 +184,7 @@ static const struct regmap_range da9063_bb_readable_ranges[] = { ...@@ -72,7 +184,7 @@ static const struct regmap_range da9063_bb_readable_ranges[] = {
regmap_reg_range(DA9063_REG_SEQ, DA9063_REG_ID_32_31), regmap_reg_range(DA9063_REG_SEQ, DA9063_REG_ID_32_31),
regmap_reg_range(DA9063_REG_SEQ_A, DA9063_REG_AUTO3_LOW), regmap_reg_range(DA9063_REG_SEQ_A, DA9063_REG_AUTO3_LOW),
regmap_reg_range(DA9063_REG_T_OFFSET, DA9063_BB_REG_GP_ID_19), regmap_reg_range(DA9063_REG_T_OFFSET, DA9063_BB_REG_GP_ID_19),
regmap_reg_range(DA9063_REG_CHIP_ID, DA9063_REG_CHIP_VARIANT), regmap_reg_range(DA9063_REG_DEVICE_ID, DA9063_REG_VARIANT_ID),
}; };
static const struct regmap_range da9063_bb_writeable_ranges[] = { static const struct regmap_range da9063_bb_writeable_ranges[] = {
...@@ -85,7 +197,7 @@ static const struct regmap_range da9063_bb_writeable_ranges[] = { ...@@ -85,7 +197,7 @@ static const struct regmap_range da9063_bb_writeable_ranges[] = {
regmap_reg_range(DA9063_BB_REG_GP_ID_0, DA9063_BB_REG_GP_ID_19), regmap_reg_range(DA9063_BB_REG_GP_ID_0, DA9063_BB_REG_GP_ID_19),
}; };
static const struct regmap_range da9063_bb_volatile_ranges[] = { static const struct regmap_range da9063_bb_da_volatile_ranges[] = {
regmap_reg_range(DA9063_REG_PAGE_CON, DA9063_REG_EVENT_D), regmap_reg_range(DA9063_REG_PAGE_CON, DA9063_REG_EVENT_D),
regmap_reg_range(DA9063_REG_CONTROL_A, DA9063_REG_CONTROL_B), regmap_reg_range(DA9063_REG_CONTROL_A, DA9063_REG_CONTROL_B),
regmap_reg_range(DA9063_REG_CONTROL_E, DA9063_REG_CONTROL_F), regmap_reg_range(DA9063_REG_CONTROL_E, DA9063_REG_CONTROL_F),
...@@ -107,9 +219,9 @@ static const struct regmap_access_table da9063_bb_writeable_table = { ...@@ -107,9 +219,9 @@ static const struct regmap_access_table da9063_bb_writeable_table = {
.n_yes_ranges = ARRAY_SIZE(da9063_bb_writeable_ranges), .n_yes_ranges = ARRAY_SIZE(da9063_bb_writeable_ranges),
}; };
static const struct regmap_access_table da9063_bb_volatile_table = { static const struct regmap_access_table da9063_bb_da_volatile_table = {
.yes_ranges = da9063_bb_volatile_ranges, .yes_ranges = da9063_bb_da_volatile_ranges,
.n_yes_ranges = ARRAY_SIZE(da9063_bb_volatile_ranges), .n_yes_ranges = ARRAY_SIZE(da9063_bb_da_volatile_ranges),
}; };
static const struct regmap_range da9063l_bb_readable_ranges[] = { static const struct regmap_range da9063l_bb_readable_ranges[] = {
...@@ -117,7 +229,7 @@ static const struct regmap_range da9063l_bb_readable_ranges[] = { ...@@ -117,7 +229,7 @@ static const struct regmap_range da9063l_bb_readable_ranges[] = {
regmap_reg_range(DA9063_REG_SEQ, DA9063_REG_ID_32_31), regmap_reg_range(DA9063_REG_SEQ, DA9063_REG_ID_32_31),
regmap_reg_range(DA9063_REG_SEQ_A, DA9063_REG_AUTO3_LOW), regmap_reg_range(DA9063_REG_SEQ_A, DA9063_REG_AUTO3_LOW),
regmap_reg_range(DA9063_REG_T_OFFSET, DA9063_BB_REG_GP_ID_19), regmap_reg_range(DA9063_REG_T_OFFSET, DA9063_BB_REG_GP_ID_19),
regmap_reg_range(DA9063_REG_CHIP_ID, DA9063_REG_CHIP_VARIANT), regmap_reg_range(DA9063_REG_DEVICE_ID, DA9063_REG_VARIANT_ID),
}; };
static const struct regmap_range da9063l_bb_writeable_ranges[] = { static const struct regmap_range da9063l_bb_writeable_ranges[] = {
...@@ -129,7 +241,7 @@ static const struct regmap_range da9063l_bb_writeable_ranges[] = { ...@@ -129,7 +241,7 @@ static const struct regmap_range da9063l_bb_writeable_ranges[] = {
regmap_reg_range(DA9063_BB_REG_GP_ID_0, DA9063_BB_REG_GP_ID_19), regmap_reg_range(DA9063_BB_REG_GP_ID_0, DA9063_BB_REG_GP_ID_19),
}; };
static const struct regmap_range da9063l_bb_volatile_ranges[] = { static const struct regmap_range da9063l_bb_da_volatile_ranges[] = {
regmap_reg_range(DA9063_REG_PAGE_CON, DA9063_REG_EVENT_D), regmap_reg_range(DA9063_REG_PAGE_CON, DA9063_REG_EVENT_D),
regmap_reg_range(DA9063_REG_CONTROL_A, DA9063_REG_CONTROL_B), regmap_reg_range(DA9063_REG_CONTROL_A, DA9063_REG_CONTROL_B),
regmap_reg_range(DA9063_REG_CONTROL_E, DA9063_REG_CONTROL_F), regmap_reg_range(DA9063_REG_CONTROL_E, DA9063_REG_CONTROL_F),
...@@ -151,15 +263,70 @@ static const struct regmap_access_table da9063l_bb_writeable_table = { ...@@ -151,15 +263,70 @@ static const struct regmap_access_table da9063l_bb_writeable_table = {
.n_yes_ranges = ARRAY_SIZE(da9063l_bb_writeable_ranges), .n_yes_ranges = ARRAY_SIZE(da9063l_bb_writeable_ranges),
}; };
static const struct regmap_access_table da9063l_bb_volatile_table = { static const struct regmap_access_table da9063l_bb_da_volatile_table = {
.yes_ranges = da9063l_bb_volatile_ranges, .yes_ranges = da9063l_bb_da_volatile_ranges,
.n_yes_ranges = ARRAY_SIZE(da9063l_bb_volatile_ranges), .n_yes_ranges = ARRAY_SIZE(da9063l_bb_da_volatile_ranges),
};
static const struct regmap_range da9063_da_readable_ranges[] = {
regmap_reg_range(DA9063_REG_PAGE_CON, DA9063_BB_REG_SECOND_D),
regmap_reg_range(DA9063_REG_SEQ, DA9063_REG_ID_32_31),
regmap_reg_range(DA9063_REG_SEQ_A, DA9063_REG_AUTO3_LOW),
regmap_reg_range(DA9063_REG_T_OFFSET, DA9063_BB_REG_GP_ID_11),
regmap_reg_range(DA9063_REG_DEVICE_ID, DA9063_REG_VARIANT_ID),
};
static const struct regmap_range da9063_da_writeable_ranges[] = {
regmap_reg_range(DA9063_REG_PAGE_CON, DA9063_REG_PAGE_CON),
regmap_reg_range(DA9063_REG_FAULT_LOG, DA9063_REG_VSYS_MON),
regmap_reg_range(DA9063_REG_COUNT_S, DA9063_BB_REG_ALARM_Y),
regmap_reg_range(DA9063_REG_SEQ, DA9063_REG_ID_32_31),
regmap_reg_range(DA9063_REG_SEQ_A, DA9063_REG_AUTO3_LOW),
regmap_reg_range(DA9063_REG_CONFIG_I, DA9063_BB_REG_MON_REG_4),
regmap_reg_range(DA9063_BB_REG_GP_ID_0, DA9063_BB_REG_GP_ID_11),
};
static const struct regmap_access_table da9063_da_readable_table = {
.yes_ranges = da9063_da_readable_ranges,
.n_yes_ranges = ARRAY_SIZE(da9063_da_readable_ranges),
};
static const struct regmap_access_table da9063_da_writeable_table = {
.yes_ranges = da9063_da_writeable_ranges,
.n_yes_ranges = ARRAY_SIZE(da9063_da_writeable_ranges),
};
static const struct regmap_range da9063l_da_readable_ranges[] = {
regmap_reg_range(DA9063_REG_PAGE_CON, DA9063_REG_MON_A10_RES),
regmap_reg_range(DA9063_REG_SEQ, DA9063_REG_ID_32_31),
regmap_reg_range(DA9063_REG_SEQ_A, DA9063_REG_AUTO3_LOW),
regmap_reg_range(DA9063_REG_T_OFFSET, DA9063_BB_REG_GP_ID_11),
regmap_reg_range(DA9063_REG_DEVICE_ID, DA9063_REG_VARIANT_ID),
};
static const struct regmap_range da9063l_da_writeable_ranges[] = {
regmap_reg_range(DA9063_REG_PAGE_CON, DA9063_REG_PAGE_CON),
regmap_reg_range(DA9063_REG_FAULT_LOG, DA9063_REG_VSYS_MON),
regmap_reg_range(DA9063_REG_SEQ, DA9063_REG_ID_32_31),
regmap_reg_range(DA9063_REG_SEQ_A, DA9063_REG_AUTO3_LOW),
regmap_reg_range(DA9063_REG_CONFIG_I, DA9063_BB_REG_MON_REG_4),
regmap_reg_range(DA9063_BB_REG_GP_ID_0, DA9063_BB_REG_GP_ID_11),
};
static const struct regmap_access_table da9063l_da_readable_table = {
.yes_ranges = da9063l_da_readable_ranges,
.n_yes_ranges = ARRAY_SIZE(da9063l_da_readable_ranges),
};
static const struct regmap_access_table da9063l_da_writeable_table = {
.yes_ranges = da9063l_da_writeable_ranges,
.n_yes_ranges = ARRAY_SIZE(da9063l_da_writeable_ranges),
}; };
static const struct regmap_range_cfg da9063_range_cfg[] = { static const struct regmap_range_cfg da9063_range_cfg[] = {
{ {
.range_min = DA9063_REG_PAGE_CON, .range_min = DA9063_REG_PAGE_CON,
.range_max = DA9063_REG_CHIP_VARIANT, .range_max = DA9063_REG_CONFIG_ID,
.selector_reg = DA9063_REG_PAGE_CON, .selector_reg = DA9063_REG_PAGE_CON,
.selector_mask = 1 << DA9063_I2C_PAGE_SEL_SHIFT, .selector_mask = 1 << DA9063_I2C_PAGE_SEL_SHIFT,
.selector_shift = DA9063_I2C_PAGE_SEL_SHIFT, .selector_shift = DA9063_I2C_PAGE_SEL_SHIFT,
...@@ -173,7 +340,7 @@ static struct regmap_config da9063_regmap_config = { ...@@ -173,7 +340,7 @@ static struct regmap_config da9063_regmap_config = {
.val_bits = 8, .val_bits = 8,
.ranges = da9063_range_cfg, .ranges = da9063_range_cfg,
.num_ranges = ARRAY_SIZE(da9063_range_cfg), .num_ranges = ARRAY_SIZE(da9063_range_cfg),
.max_register = DA9063_REG_CHIP_VARIANT, .max_register = DA9063_REG_CONFIG_ID,
.cache_type = REGCACHE_RBTREE, .cache_type = REGCACHE_RBTREE,
}; };
...@@ -199,18 +366,72 @@ static int da9063_i2c_probe(struct i2c_client *i2c, ...@@ -199,18 +366,72 @@ static int da9063_i2c_probe(struct i2c_client *i2c,
da9063->chip_irq = i2c->irq; da9063->chip_irq = i2c->irq;
da9063->type = id->driver_data; da9063->type = id->driver_data;
if (da9063->variant_code == PMIC_DA9063_AD) { ret = da9063_get_device_type(i2c, da9063);
da9063_regmap_config.rd_table = &da9063_ad_readable_table; if (ret)
da9063_regmap_config.wr_table = &da9063_ad_writeable_table; return ret;
da9063_regmap_config.volatile_table = &da9063_ad_volatile_table;
} else if (da9063->type == PMIC_TYPE_DA9063L) { switch (da9063->type) {
da9063_regmap_config.rd_table = &da9063l_bb_readable_table; case PMIC_TYPE_DA9063:
da9063_regmap_config.wr_table = &da9063l_bb_writeable_table; switch (da9063->variant_code) {
da9063_regmap_config.volatile_table = &da9063l_bb_volatile_table; case PMIC_DA9063_AD:
} else { da9063_regmap_config.rd_table =
da9063_regmap_config.rd_table = &da9063_bb_readable_table; &da9063_ad_readable_table;
da9063_regmap_config.wr_table = &da9063_bb_writeable_table; da9063_regmap_config.wr_table =
da9063_regmap_config.volatile_table = &da9063_bb_volatile_table; &da9063_ad_writeable_table;
da9063_regmap_config.volatile_table =
&da9063_ad_volatile_table;
break;
case PMIC_DA9063_BB:
case PMIC_DA9063_CA:
da9063_regmap_config.rd_table =
&da9063_bb_readable_table;
da9063_regmap_config.wr_table =
&da9063_bb_writeable_table;
da9063_regmap_config.volatile_table =
&da9063_bb_da_volatile_table;
break;
case PMIC_DA9063_DA:
da9063_regmap_config.rd_table =
&da9063_da_readable_table;
da9063_regmap_config.wr_table =
&da9063_da_writeable_table;
da9063_regmap_config.volatile_table =
&da9063_bb_da_volatile_table;
break;
default:
dev_err(da9063->dev,
"Chip variant not supported for DA9063\n");
return -ENODEV;
}
break;
case PMIC_TYPE_DA9063L:
switch (da9063->variant_code) {
case PMIC_DA9063_BB:
case PMIC_DA9063_CA:
da9063_regmap_config.rd_table =
&da9063l_bb_readable_table;
da9063_regmap_config.wr_table =
&da9063l_bb_writeable_table;
da9063_regmap_config.volatile_table =
&da9063l_bb_da_volatile_table;
break;
case PMIC_DA9063_DA:
da9063_regmap_config.rd_table =
&da9063l_da_readable_table;
da9063_regmap_config.wr_table =
&da9063l_da_writeable_table;
da9063_regmap_config.volatile_table =
&da9063l_bb_da_volatile_table;
break;
default:
dev_err(da9063->dev,
"Chip variant not supported for DA9063L\n");
return -ENODEV;
}
break;
default:
dev_err(da9063->dev, "Chip type not supported\n");
return -ENODEV;
} }
da9063->regmap = devm_regmap_init_i2c(i2c, &da9063_regmap_config); da9063->regmap = devm_regmap_init_i2c(i2c, &da9063_regmap_config);
......
...@@ -2276,6 +2276,8 @@ bool db8500_prcmu_is_ac_wake_requested(void) ...@@ -2276,6 +2276,8 @@ bool db8500_prcmu_is_ac_wake_requested(void)
* *
* Saves the reset reason code and then sets the APE_SOFTRST register which * Saves the reset reason code and then sets the APE_SOFTRST register which
* fires interrupt to fw * fires interrupt to fw
*
* @reset_code: The reason for system reset
*/ */
void db8500_prcmu_system_reset(u16 reset_code) void db8500_prcmu_system_reset(u16 reset_code)
{ {
...@@ -3004,10 +3006,6 @@ static int db8500_prcmu_register_ab8500(struct device *parent) ...@@ -3004,10 +3006,6 @@ static int db8500_prcmu_register_ab8500(struct device *parent)
return mfd_add_devices(parent, 0, ab850x_cell, 1, NULL, 0, NULL); return mfd_add_devices(parent, 0, ab850x_cell, 1, NULL, 0, NULL);
} }
/**
* prcmu_fw_init - arch init call for the Linux PRCMU fw init logic
*
*/
static int db8500_prcmu_probe(struct platform_device *pdev) static int db8500_prcmu_probe(struct platform_device *pdev)
{ {
struct device_node *np = pdev->dev.of_node; struct device_node *np = pdev->dev.of_node;
......
...@@ -287,7 +287,11 @@ static void dln2_rx(struct urb *urb) ...@@ -287,7 +287,11 @@ static void dln2_rx(struct urb *urb)
len = urb->actual_length - sizeof(struct dln2_header); len = urb->actual_length - sizeof(struct dln2_header);
if (handle == DLN2_HANDLE_EVENT) { if (handle == DLN2_HANDLE_EVENT) {
unsigned long flags;
spin_lock_irqsave(&dln2->event_cb_lock, flags);
dln2_run_event_callbacks(dln2, id, echo, data, len); dln2_run_event_callbacks(dln2, id, echo, data, len);
spin_unlock_irqrestore(&dln2->event_cb_lock, flags);
} else { } else {
/* URB will be re-submitted in _dln2_transfer (free_rx_slot) */ /* URB will be re-submitted in _dln2_transfer (free_rx_slot) */
if (dln2_transfer_complete(dln2, urb, handle, echo)) if (dln2_transfer_complete(dln2, urb, handle, echo))
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* Copyright (c) <2011-2014> HiSilicon Technologies Co., Ltd. * Copyright (c) <2011-2014> HiSilicon Technologies Co., Ltd.
* http://www.hisilicon.com * http://www.hisilicon.com
* Copyright (c) <2013-2017> Linaro Ltd. * Copyright (c) <2013-2017> Linaro Ltd.
* http://www.linaro.org * https://www.linaro.org
* *
* Author: Guodong Xu <guodong.xu@linaro.org> * Author: Guodong Xu <guodong.xu@linaro.org>
*/ */
......
...@@ -201,6 +201,9 @@ static const struct pci_device_id intel_lpss_pci_ids[] = { ...@@ -201,6 +201,9 @@ static const struct pci_device_id intel_lpss_pci_ids[] = {
{ PCI_VDEVICE(INTEL, 0x1ac4), (kernel_ulong_t)&bxt_info }, { PCI_VDEVICE(INTEL, 0x1ac4), (kernel_ulong_t)&bxt_info },
{ PCI_VDEVICE(INTEL, 0x1ac6), (kernel_ulong_t)&bxt_info }, { PCI_VDEVICE(INTEL, 0x1ac6), (kernel_ulong_t)&bxt_info },
{ PCI_VDEVICE(INTEL, 0x1aee), (kernel_ulong_t)&bxt_uart_info }, { PCI_VDEVICE(INTEL, 0x1aee), (kernel_ulong_t)&bxt_uart_info },
/* EBG */
{ PCI_VDEVICE(INTEL, 0x1bad), (kernel_ulong_t)&bxt_uart_info },
{ PCI_VDEVICE(INTEL, 0x1bae), (kernel_ulong_t)&bxt_uart_info },
/* GLK */ /* GLK */
{ PCI_VDEVICE(INTEL, 0x31ac), (kernel_ulong_t)&glk_i2c_info }, { PCI_VDEVICE(INTEL, 0x31ac), (kernel_ulong_t)&glk_i2c_info },
{ PCI_VDEVICE(INTEL, 0x31ae), (kernel_ulong_t)&glk_i2c_info }, { PCI_VDEVICE(INTEL, 0x31ae), (kernel_ulong_t)&glk_i2c_info },
...@@ -230,6 +233,22 @@ static const struct pci_device_id intel_lpss_pci_ids[] = { ...@@ -230,6 +233,22 @@ static const struct pci_device_id intel_lpss_pci_ids[] = {
{ PCI_VDEVICE(INTEL, 0x34ea), (kernel_ulong_t)&bxt_i2c_info }, { PCI_VDEVICE(INTEL, 0x34ea), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x34eb), (kernel_ulong_t)&bxt_i2c_info }, { PCI_VDEVICE(INTEL, 0x34eb), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x34fb), (kernel_ulong_t)&spt_info }, { PCI_VDEVICE(INTEL, 0x34fb), (kernel_ulong_t)&spt_info },
/* TGL-H */
{ PCI_VDEVICE(INTEL, 0x43a7), (kernel_ulong_t)&bxt_uart_info },
{ PCI_VDEVICE(INTEL, 0x43a8), (kernel_ulong_t)&bxt_uart_info },
{ PCI_VDEVICE(INTEL, 0x43a9), (kernel_ulong_t)&bxt_uart_info },
{ PCI_VDEVICE(INTEL, 0x43aa), (kernel_ulong_t)&bxt_info },
{ PCI_VDEVICE(INTEL, 0x43ab), (kernel_ulong_t)&bxt_info },
{ PCI_VDEVICE(INTEL, 0x43ad), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x43ae), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x43d8), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x43da), (kernel_ulong_t)&bxt_uart_info },
{ PCI_VDEVICE(INTEL, 0x43e8), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x43e9), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x43ea), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x43eb), (kernel_ulong_t)&bxt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x43fb), (kernel_ulong_t)&bxt_info },
{ PCI_VDEVICE(INTEL, 0x43fd), (kernel_ulong_t)&bxt_info },
/* EHL */ /* EHL */
{ PCI_VDEVICE(INTEL, 0x4b28), (kernel_ulong_t)&bxt_uart_info }, { PCI_VDEVICE(INTEL, 0x4b28), (kernel_ulong_t)&bxt_uart_info },
{ PCI_VDEVICE(INTEL, 0x4b29), (kernel_ulong_t)&bxt_uart_info }, { PCI_VDEVICE(INTEL, 0x4b29), (kernel_ulong_t)&bxt_uart_info },
......
...@@ -91,13 +91,8 @@ static int bcove_ipc_byte_reg_write(void *context, unsigned int reg, ...@@ -91,13 +91,8 @@ static int bcove_ipc_byte_reg_write(void *context, unsigned int reg,
{ {
struct intel_soc_pmic *pmic = context; struct intel_soc_pmic *pmic = context;
u8 ipc_in = val; u8 ipc_in = val;
int ret;
ret = intel_scu_ipc_dev_iowrite8(pmic->scu, reg, ipc_in); return intel_scu_ipc_dev_iowrite8(pmic->scu, reg, ipc_in);
if (ret)
return ret;
return 0;
} }
static const struct regmap_config bcove_regmap_config = { static const struct regmap_config bcove_regmap_config = {
......
...@@ -79,39 +79,31 @@ enum kempld_cells { ...@@ -79,39 +79,31 @@ enum kempld_cells {
KEMPLD_UART, KEMPLD_UART,
}; };
static const struct mfd_cell kempld_devs[] = { static const char *kempld_dev_names[] = {
[KEMPLD_I2C] = { [KEMPLD_I2C] = "kempld-i2c",
.name = "kempld-i2c", [KEMPLD_WDT] = "kempld-wdt",
}, [KEMPLD_GPIO] = "kempld-gpio",
[KEMPLD_WDT] = { [KEMPLD_UART] = "kempld-uart",
.name = "kempld-wdt",
},
[KEMPLD_GPIO] = {
.name = "kempld-gpio",
},
[KEMPLD_UART] = {
.name = "kempld-uart",
},
}; };
#define KEMPLD_MAX_DEVS ARRAY_SIZE(kempld_devs) #define KEMPLD_MAX_DEVS ARRAY_SIZE(kempld_dev_names)
static int kempld_register_cells_generic(struct kempld_device_data *pld) static int kempld_register_cells_generic(struct kempld_device_data *pld)
{ {
struct mfd_cell devs[KEMPLD_MAX_DEVS]; struct mfd_cell devs[KEMPLD_MAX_DEVS] = {};
int i = 0; int i = 0;
if (pld->feature_mask & KEMPLD_FEATURE_BIT_I2C) if (pld->feature_mask & KEMPLD_FEATURE_BIT_I2C)
devs[i++] = kempld_devs[KEMPLD_I2C]; devs[i++].name = kempld_dev_names[KEMPLD_I2C];
if (pld->feature_mask & KEMPLD_FEATURE_BIT_WATCHDOG) if (pld->feature_mask & KEMPLD_FEATURE_BIT_WATCHDOG)
devs[i++] = kempld_devs[KEMPLD_WDT]; devs[i++].name = kempld_dev_names[KEMPLD_WDT];
if (pld->feature_mask & KEMPLD_FEATURE_BIT_GPIO) if (pld->feature_mask & KEMPLD_FEATURE_BIT_GPIO)
devs[i++] = kempld_devs[KEMPLD_GPIO]; devs[i++].name = kempld_dev_names[KEMPLD_GPIO];
if (pld->feature_mask & KEMPLD_FEATURE_MASK_UART) if (pld->feature_mask & KEMPLD_FEATURE_MASK_UART)
devs[i++] = kempld_devs[KEMPLD_UART]; devs[i++].name = kempld_dev_names[KEMPLD_UART];
return mfd_add_devices(pld->dev, -1, devs, i, NULL, 0, NULL); return mfd_add_devices(pld->dev, -1, devs, i, NULL, 0, NULL);
} }
......
// SPDX-License-Identifier: GPL-2.0
/*
* Driver for Khadas System control Microcontroller
*
* Copyright (C) 2020 BayLibre SAS
*
* Author(s): Neil Armstrong <narmstrong@baylibre.com>
*/
#include <linux/bitfield.h>
#include <linux/i2c.h>
#include <linux/mfd/core.h>
#include <linux/mfd/khadas-mcu.h>
#include <linux/module.h>
#include <linux/regmap.h>
static bool khadas_mcu_reg_volatile(struct device *dev, unsigned int reg)
{
if (reg >= KHADAS_MCU_USER_DATA_0_REG &&
reg < KHADAS_MCU_PWR_OFF_CMD_REG)
return true;
switch (reg) {
case KHADAS_MCU_PWR_OFF_CMD_REG:
case KHADAS_MCU_PASSWD_START_REG:
case KHADAS_MCU_CHECK_VEN_PASSWD_REG:
case KHADAS_MCU_CHECK_USER_PASSWD_REG:
case KHADAS_MCU_WOL_INIT_START_REG:
case KHADAS_MCU_CMD_FAN_STATUS_CTRL_REG:
return true;
default:
return false;
}
}
static bool khadas_mcu_reg_writeable(struct device *dev, unsigned int reg)
{
switch (reg) {
case KHADAS_MCU_PASSWD_VEN_0_REG:
case KHADAS_MCU_PASSWD_VEN_1_REG:
case KHADAS_MCU_PASSWD_VEN_2_REG:
case KHADAS_MCU_PASSWD_VEN_3_REG:
case KHADAS_MCU_PASSWD_VEN_4_REG:
case KHADAS_MCU_PASSWD_VEN_5_REG:
case KHADAS_MCU_MAC_0_REG:
case KHADAS_MCU_MAC_1_REG:
case KHADAS_MCU_MAC_2_REG:
case KHADAS_MCU_MAC_3_REG:
case KHADAS_MCU_MAC_4_REG:
case KHADAS_MCU_MAC_5_REG:
case KHADAS_MCU_USID_0_REG:
case KHADAS_MCU_USID_1_REG:
case KHADAS_MCU_USID_2_REG:
case KHADAS_MCU_USID_3_REG:
case KHADAS_MCU_USID_4_REG:
case KHADAS_MCU_USID_5_REG:
case KHADAS_MCU_VERSION_0_REG:
case KHADAS_MCU_VERSION_1_REG:
case KHADAS_MCU_DEVICE_NO_0_REG:
case KHADAS_MCU_DEVICE_NO_1_REG:
case KHADAS_MCU_FACTORY_TEST_REG:
case KHADAS_MCU_SHUTDOWN_NORMAL_STATUS_REG:
return false;
default:
return true;
}
}
static const struct regmap_config khadas_mcu_regmap_config = {
.reg_bits = 8,
.reg_stride = 1,
.val_bits = 8,
.max_register = KHADAS_MCU_CMD_FAN_STATUS_CTRL_REG,
.volatile_reg = khadas_mcu_reg_volatile,
.writeable_reg = khadas_mcu_reg_writeable,
.cache_type = REGCACHE_RBTREE,
};
static struct mfd_cell khadas_mcu_fan_cells[] = {
/* VIM1/2 Rev13+ and VIM3 only */
{ .name = "khadas-mcu-fan-ctrl", },
};
static struct mfd_cell khadas_mcu_cells[] = {
{ .name = "khadas-mcu-user-mem", },
};
static int khadas_mcu_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct device *dev = &client->dev;
struct khadas_mcu *ddata;
int ret;
ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL);
if (!ddata)
return -ENOMEM;
i2c_set_clientdata(client, ddata);
ddata->dev = dev;
ddata->regmap = devm_regmap_init_i2c(client, &khadas_mcu_regmap_config);
if (IS_ERR(ddata->regmap)) {
ret = PTR_ERR(ddata->regmap);
dev_err(dev, "Failed to allocate register map: %d\n", ret);
return ret;
}
ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE,
khadas_mcu_cells,
ARRAY_SIZE(khadas_mcu_cells),
NULL, 0, NULL);
if (ret)
return ret;
if (of_find_property(dev->of_node, "#cooling-cells", NULL))
return devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE,
khadas_mcu_fan_cells,
ARRAY_SIZE(khadas_mcu_fan_cells),
NULL, 0, NULL);
return 0;
}
static const struct of_device_id khadas_mcu_of_match[] = {
{ .compatible = "khadas,mcu", },
{},
};
MODULE_DEVICE_TABLE(of, khadas_mcu_of_match);
static struct i2c_driver khadas_mcu_driver = {
.driver = {
.name = "khadas-mcu-core",
.of_match_table = of_match_ptr(khadas_mcu_of_match),
},
.probe = khadas_mcu_probe,
};
module_i2c_driver(khadas_mcu_driver);
MODULE_DESCRIPTION("Khadas MCU core driver");
MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
MODULE_LICENSE("GPL v2");
...@@ -17,7 +17,6 @@ ...@@ -17,7 +17,6 @@
#define LM3533_MAX_CURRENT_MAX 29800 #define LM3533_MAX_CURRENT_MAX 29800
#define LM3533_MAX_CURRENT_STEP 800 #define LM3533_MAX_CURRENT_STEP 800
#define LM3533_BRIGHTNESS_MAX 255
#define LM3533_PWM_MAX 0x3f #define LM3533_PWM_MAX 0x3f
#define LM3533_REG_PWM_BASE 0x14 #define LM3533_REG_PWM_BASE 0x14
...@@ -89,41 +88,33 @@ int lm3533_ctrlbank_set_max_current(struct lm3533_ctrlbank *cb, u16 imax) ...@@ -89,41 +88,33 @@ int lm3533_ctrlbank_set_max_current(struct lm3533_ctrlbank *cb, u16 imax)
} }
EXPORT_SYMBOL_GPL(lm3533_ctrlbank_set_max_current); EXPORT_SYMBOL_GPL(lm3533_ctrlbank_set_max_current);
#define lm3533_ctrlbank_set(_name, _NAME) \ int lm3533_ctrlbank_set_brightness(struct lm3533_ctrlbank *cb, u8 val)
int lm3533_ctrlbank_set_##_name(struct lm3533_ctrlbank *cb, u8 val) \ {
{ \ u8 reg;
u8 reg; \ int ret;
int ret; \
\ reg = lm3533_ctrlbank_get_reg(cb, LM3533_REG_BRIGHTNESS_BASE);
if (val > LM3533_##_NAME##_MAX) \ ret = lm3533_write(cb->lm3533, reg, val);
return -EINVAL; \ if (ret)
\ dev_err(cb->dev, "failed to set brightness\n");
reg = lm3533_ctrlbank_get_reg(cb, LM3533_REG_##_NAME##_BASE); \
ret = lm3533_write(cb->lm3533, reg, val); \ return ret;
if (ret) \ }
dev_err(cb->dev, "failed to set " #_name "\n"); \ EXPORT_SYMBOL_GPL(lm3533_ctrlbank_set_brightness);
\
return ret; \ int lm3533_ctrlbank_get_brightness(struct lm3533_ctrlbank *cb, u8 *val)
} \ {
EXPORT_SYMBOL_GPL(lm3533_ctrlbank_set_##_name); u8 reg;
int ret;
#define lm3533_ctrlbank_get(_name, _NAME) \
int lm3533_ctrlbank_get_##_name(struct lm3533_ctrlbank *cb, u8 *val) \ reg = lm3533_ctrlbank_get_reg(cb, LM3533_REG_BRIGHTNESS_BASE);
{ \ ret = lm3533_read(cb->lm3533, reg, val);
u8 reg; \ if (ret)
int ret; \ dev_err(cb->dev, "failed to get brightness\n");
\
reg = lm3533_ctrlbank_get_reg(cb, LM3533_REG_##_NAME##_BASE); \ return ret;
ret = lm3533_read(cb->lm3533, reg, val); \ }
if (ret) \ EXPORT_SYMBOL_GPL(lm3533_ctrlbank_get_brightness);
dev_err(cb->dev, "failed to get " #_name "\n"); \
\
return ret; \
} \
EXPORT_SYMBOL_GPL(lm3533_ctrlbank_get_##_name);
lm3533_ctrlbank_set(brightness, BRIGHTNESS);
lm3533_ctrlbank_get(brightness, BRIGHTNESS);
/* /*
* PWM-input control mask: * PWM-input control mask:
...@@ -135,9 +126,36 @@ lm3533_ctrlbank_get(brightness, BRIGHTNESS); ...@@ -135,9 +126,36 @@ lm3533_ctrlbank_get(brightness, BRIGHTNESS);
* bit 1 - PWM-input enabled in Zone 0 * bit 1 - PWM-input enabled in Zone 0
* bit 0 - PWM-input enabled * bit 0 - PWM-input enabled
*/ */
lm3533_ctrlbank_set(pwm, PWM); int lm3533_ctrlbank_set_pwm(struct lm3533_ctrlbank *cb, u8 val)
lm3533_ctrlbank_get(pwm, PWM); {
u8 reg;
int ret;
if (val > LM3533_PWM_MAX)
return -EINVAL;
reg = lm3533_ctrlbank_get_reg(cb, LM3533_REG_PWM_BASE);
ret = lm3533_write(cb->lm3533, reg, val);
if (ret)
dev_err(cb->dev, "failed to set PWM mask\n");
return ret;
}
EXPORT_SYMBOL_GPL(lm3533_ctrlbank_set_pwm);
int lm3533_ctrlbank_get_pwm(struct lm3533_ctrlbank *cb, u8 *val)
{
u8 reg;
int ret;
reg = lm3533_ctrlbank_get_reg(cb, LM3533_REG_PWM_BASE);
ret = lm3533_read(cb->lm3533, reg, val);
if (ret)
dev_err(cb->dev, "failed to get PWM mask\n");
return ret;
}
EXPORT_SYMBOL_GPL(lm3533_ctrlbank_get_pwm);
MODULE_AUTHOR("Johan Hovold <jhovold@gmail.com>"); MODULE_AUTHOR("Johan Hovold <jhovold@gmail.com>");
MODULE_DESCRIPTION("LM3533 Control Bank interface"); MODULE_DESCRIPTION("LM3533 Control Bank interface");
......
/* /*
* Copyright (C) 2016 Texas Instruments Incorporated - http://www.ti.com/ * Copyright (C) 2016 Texas Instruments Incorporated - https://www.ti.com/
* *
* Author: Keerthy <j-keerthy@ti.com> * Author: Keerthy <j-keerthy@ti.com>
* *
......
// SPDX-License-Identifier: GPL-2.0-only // SPDX-License-Identifier: GPL-2.0-only
/* /*
* Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com/ * Copyright (C) 2017 Texas Instruments Incorporated - https://www.ti.com/
* *
* Author: Keerthy <j-keerthy@ti.com> * Author: Keerthy <j-keerthy@ti.com>
*/ */
......
...@@ -44,7 +44,10 @@ static const char * const madera_core_supplies[] = { ...@@ -44,7 +44,10 @@ static const char * const madera_core_supplies[] = {
}; };
static const struct mfd_cell madera_ldo1_devs[] = { static const struct mfd_cell madera_ldo1_devs[] = {
{ .name = "madera-ldo1" }, {
.name = "madera-ldo1",
.level = MFD_DEP_LEVEL_HIGH,
},
}; };
static const char * const cs47l15_supplies[] = { static const char * const cs47l15_supplies[] = {
...@@ -55,8 +58,8 @@ static const char * const cs47l15_supplies[] = { ...@@ -55,8 +58,8 @@ static const char * const cs47l15_supplies[] = {
static const struct mfd_cell cs47l15_devs[] = { static const struct mfd_cell cs47l15_devs[] = {
{ .name = "madera-pinctrl", }, { .name = "madera-pinctrl", },
{ .name = "madera-irq" }, { .name = "madera-irq", },
{ .name = "madera-gpio" }, { .name = "madera-gpio", },
{ {
.name = "madera-extcon", .name = "madera-extcon",
.parent_supplies = cs47l15_supplies, .parent_supplies = cs47l15_supplies,
...@@ -108,7 +111,7 @@ static const char * const cs47l85_supplies[] = { ...@@ -108,7 +111,7 @@ static const char * const cs47l85_supplies[] = {
static const struct mfd_cell cs47l85_devs[] = { static const struct mfd_cell cs47l85_devs[] = {
{ .name = "madera-pinctrl", }, { .name = "madera-pinctrl", },
{ .name = "madera-irq", }, { .name = "madera-irq", },
{ .name = "madera-micsupp" }, { .name = "madera-micsupp", },
{ .name = "madera-gpio", }, { .name = "madera-gpio", },
{ {
.name = "madera-extcon", .name = "madera-extcon",
...@@ -155,10 +158,10 @@ static const char * const cs47l92_supplies[] = { ...@@ -155,10 +158,10 @@ static const char * const cs47l92_supplies[] = {
}; };
static const struct mfd_cell cs47l92_devs[] = { static const struct mfd_cell cs47l92_devs[] = {
{ .name = "madera-pinctrl" }, { .name = "madera-pinctrl", },
{ .name = "madera-irq", }, { .name = "madera-irq", },
{ .name = "madera-micsupp", }, { .name = "madera-micsupp", },
{ .name = "madera-gpio" }, { .name = "madera-gpio", },
{ {
.name = "madera-extcon", .name = "madera-extcon",
.parent_supplies = cs47l92_supplies, .parent_supplies = cs47l92_supplies,
...@@ -743,18 +746,22 @@ int madera_dev_exit(struct madera *madera) ...@@ -743,18 +746,22 @@ int madera_dev_exit(struct madera *madera)
/* Prevent any IRQs being serviced while we clean up */ /* Prevent any IRQs being serviced while we clean up */
disable_irq(madera->irq); disable_irq(madera->irq);
/* pm_runtime_get_sync(madera->dev);
* DCVDD could be supplied by a child node, we must disable it before
* removing the children, and prevent PM runtime from turning it back on
*/
pm_runtime_disable(madera->dev);
clk_disable_unprepare(madera->mclk[MADERA_MCLK2].clk); mfd_remove_devices(madera->dev);
pm_runtime_disable(madera->dev);
regulator_disable(madera->dcvdd); regulator_disable(madera->dcvdd);
regulator_put(madera->dcvdd); regulator_put(madera->dcvdd);
mfd_remove_devices(madera->dev); mfd_remove_devices_late(madera->dev);
pm_runtime_set_suspended(madera->dev);
pm_runtime_put_noidle(madera->dev);
clk_disable_unprepare(madera->mclk[MADERA_MCLK2].clk);
madera_enable_hard_reset(madera); madera_enable_hard_reset(madera);
regulator_bulk_disable(madera->num_core_supplies, regulator_bulk_disable(madera->num_core_supplies,
......
...@@ -88,7 +88,6 @@ static int madera_i2c_probe(struct i2c_client *i2c, ...@@ -88,7 +88,6 @@ static int madera_i2c_probe(struct i2c_client *i2c,
if (!madera) if (!madera)
return -ENOMEM; return -ENOMEM;
madera->regmap = devm_regmap_init_i2c(i2c, regmap_16bit_config); madera->regmap = devm_regmap_init_i2c(i2c, regmap_16bit_config);
if (IS_ERR(madera->regmap)) { if (IS_ERR(madera->regmap)) {
ret = PTR_ERR(madera->regmap); ret = PTR_ERR(madera->regmap);
......
...@@ -61,7 +61,7 @@ EXPORT_SYMBOL_GPL(maxim_charger_currents); ...@@ -61,7 +61,7 @@ EXPORT_SYMBOL_GPL(maxim_charger_currents);
int maxim_charger_calc_reg_current(const struct maxim_charger_current *limits, int maxim_charger_calc_reg_current(const struct maxim_charger_current *limits,
unsigned int min_ua, unsigned int max_ua, u8 *dst) unsigned int min_ua, unsigned int max_ua, u8 *dst)
{ {
unsigned int current_bits = 0xf; unsigned int current_bits;
if (min_ua > max_ua) if (min_ua > max_ua)
return -EINVAL; return -EINVAL;
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/list.h>
#include <linux/property.h> #include <linux/property.h>
#include <linux/mfd/core.h> #include <linux/mfd/core.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
...@@ -17,8 +18,17 @@ ...@@ -17,8 +18,17 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/irqdomain.h> #include <linux/irqdomain.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_address.h>
#include <linux/regulator/consumer.h> #include <linux/regulator/consumer.h>
static LIST_HEAD(mfd_of_node_list);
struct mfd_of_node_entry {
struct list_head list;
struct device *dev;
struct device_node *np;
};
static struct device_type mfd_dev_type = { static struct device_type mfd_dev_type = {
.name = "mfd_device", .name = "mfd_device",
}; };
...@@ -107,6 +117,55 @@ static inline void mfd_acpi_add_device(const struct mfd_cell *cell, ...@@ -107,6 +117,55 @@ static inline void mfd_acpi_add_device(const struct mfd_cell *cell,
} }
#endif #endif
static int mfd_match_of_node_to_dev(struct platform_device *pdev,
struct device_node *np,
const struct mfd_cell *cell)
{
#if IS_ENABLED(CONFIG_OF)
struct mfd_of_node_entry *of_entry;
const __be32 *reg;
u64 of_node_addr;
/* Skip devices 'disabled' by Device Tree */
if (!of_device_is_available(np))
return -ENODEV;
/* Skip if OF node has previously been allocated to a device */
list_for_each_entry(of_entry, &mfd_of_node_list, list)
if (of_entry->np == np)
return -EAGAIN;
if (!cell->use_of_reg)
/* No of_reg defined - allocate first free compatible match */
goto allocate_of_node;
/* We only care about each node's first defined address */
reg = of_get_address(np, 0, NULL, NULL);
if (!reg)
/* OF node does not contatin a 'reg' property to match to */
return -EAGAIN;
of_node_addr = of_read_number(reg, of_n_addr_cells(np));
if (cell->of_reg != of_node_addr)
/* No match */
return -EAGAIN;
allocate_of_node:
of_entry = kzalloc(sizeof(*of_entry), GFP_KERNEL);
if (!of_entry)
return -ENOMEM;
of_entry->dev = &pdev->dev;
of_entry->np = np;
list_add_tail(&of_entry->list, &mfd_of_node_list);
pdev->dev.of_node = np;
pdev->dev.fwnode = &np->fwnode;
#endif
return 0;
}
static int mfd_add_device(struct device *parent, int id, static int mfd_add_device(struct device *parent, int id,
const struct mfd_cell *cell, const struct mfd_cell *cell,
struct resource *mem_base, struct resource *mem_base,
...@@ -115,6 +174,7 @@ static int mfd_add_device(struct device *parent, int id, ...@@ -115,6 +174,7 @@ static int mfd_add_device(struct device *parent, int id,
struct resource *res; struct resource *res;
struct platform_device *pdev; struct platform_device *pdev;
struct device_node *np = NULL; struct device_node *np = NULL;
struct mfd_of_node_entry *of_entry, *tmp;
int ret = -ENOMEM; int ret = -ENOMEM;
int platform_id; int platform_id;
int r; int r;
...@@ -149,19 +209,22 @@ static int mfd_add_device(struct device *parent, int id, ...@@ -149,19 +209,22 @@ static int mfd_add_device(struct device *parent, int id,
if (ret < 0) if (ret < 0)
goto fail_res; goto fail_res;
if (parent->of_node && cell->of_compatible) { if (IS_ENABLED(CONFIG_OF) && parent->of_node && cell->of_compatible) {
for_each_child_of_node(parent->of_node, np) { for_each_child_of_node(parent->of_node, np) {
if (of_device_is_compatible(np, cell->of_compatible)) { if (of_device_is_compatible(np, cell->of_compatible)) {
if (!of_device_is_available(np)) { ret = mfd_match_of_node_to_dev(pdev, np, cell);
/* Ignore disabled devices error free */ if (ret == -EAGAIN)
ret = 0; continue;
if (ret)
goto fail_alias; goto fail_alias;
}
pdev->dev.of_node = np;
pdev->dev.fwnode = &np->fwnode;
break; break;
} }
} }
if (!pdev->dev.of_node)
pr_warn("%s: Failed to locate of_node [id: %d]\n",
cell->name, platform_id);
} }
mfd_acpi_add_device(cell, pdev); mfd_acpi_add_device(cell, pdev);
...@@ -170,13 +233,13 @@ static int mfd_add_device(struct device *parent, int id, ...@@ -170,13 +233,13 @@ static int mfd_add_device(struct device *parent, int id,
ret = platform_device_add_data(pdev, ret = platform_device_add_data(pdev,
cell->platform_data, cell->pdata_size); cell->platform_data, cell->pdata_size);
if (ret) if (ret)
goto fail_alias; goto fail_of_entry;
} }
if (cell->properties) { if (cell->properties) {
ret = platform_device_add_properties(pdev, cell->properties); ret = platform_device_add_properties(pdev, cell->properties);
if (ret) if (ret)
goto fail_alias; goto fail_of_entry;
} }
for (r = 0; r < cell->num_resources; r++) { for (r = 0; r < cell->num_resources; r++) {
...@@ -213,18 +276,18 @@ static int mfd_add_device(struct device *parent, int id, ...@@ -213,18 +276,18 @@ static int mfd_add_device(struct device *parent, int id,
if (has_acpi_companion(&pdev->dev)) { if (has_acpi_companion(&pdev->dev)) {
ret = acpi_check_resource_conflict(&res[r]); ret = acpi_check_resource_conflict(&res[r]);
if (ret) if (ret)
goto fail_alias; goto fail_of_entry;
} }
} }
} }
ret = platform_device_add_resources(pdev, res, cell->num_resources); ret = platform_device_add_resources(pdev, res, cell->num_resources);
if (ret) if (ret)
goto fail_alias; goto fail_of_entry;
ret = platform_device_add(pdev); ret = platform_device_add(pdev);
if (ret) if (ret)
goto fail_alias; goto fail_of_entry;
if (cell->pm_runtime_no_callbacks) if (cell->pm_runtime_no_callbacks)
pm_runtime_no_callbacks(&pdev->dev); pm_runtime_no_callbacks(&pdev->dev);
...@@ -233,6 +296,12 @@ static int mfd_add_device(struct device *parent, int id, ...@@ -233,6 +296,12 @@ static int mfd_add_device(struct device *parent, int id,
return 0; return 0;
fail_of_entry:
list_for_each_entry_safe(of_entry, tmp, &mfd_of_node_list, list)
if (of_entry->dev == &pdev->dev) {
list_del(&of_entry->list);
kfree(of_entry);
}
fail_alias: fail_alias:
regulator_bulk_unregister_supply_alias(&pdev->dev, regulator_bulk_unregister_supply_alias(&pdev->dev,
cell->parent_supplies, cell->parent_supplies,
...@@ -287,6 +356,7 @@ static int mfd_remove_devices_fn(struct device *dev, void *data) ...@@ -287,6 +356,7 @@ static int mfd_remove_devices_fn(struct device *dev, void *data)
{ {
struct platform_device *pdev; struct platform_device *pdev;
const struct mfd_cell *cell; const struct mfd_cell *cell;
int *level = data;
if (dev->type != &mfd_dev_type) if (dev->type != &mfd_dev_type)
return 0; return 0;
...@@ -294,16 +364,31 @@ static int mfd_remove_devices_fn(struct device *dev, void *data) ...@@ -294,16 +364,31 @@ static int mfd_remove_devices_fn(struct device *dev, void *data)
pdev = to_platform_device(dev); pdev = to_platform_device(dev);
cell = mfd_get_cell(pdev); cell = mfd_get_cell(pdev);
if (level && cell->level > *level)
return 0;
regulator_bulk_unregister_supply_alias(dev, cell->parent_supplies, regulator_bulk_unregister_supply_alias(dev, cell->parent_supplies,
cell->num_parent_supplies); cell->num_parent_supplies);
kfree(cell);
platform_device_unregister(pdev); platform_device_unregister(pdev);
return 0; return 0;
} }
void mfd_remove_devices_late(struct device *parent)
{
int level = MFD_DEP_LEVEL_HIGH;
device_for_each_child_reverse(parent, &level, mfd_remove_devices_fn);
}
EXPORT_SYMBOL(mfd_remove_devices_late);
void mfd_remove_devices(struct device *parent) void mfd_remove_devices(struct device *parent)
{ {
device_for_each_child_reverse(parent, NULL, mfd_remove_devices_fn); int level = MFD_DEP_LEVEL_NORMAL;
device_for_each_child_reverse(parent, &level, mfd_remove_devices_fn);
} }
EXPORT_SYMBOL(mfd_remove_devices); EXPORT_SYMBOL(mfd_remove_devices);
...@@ -318,6 +403,16 @@ static void devm_mfd_dev_release(struct device *dev, void *res) ...@@ -318,6 +403,16 @@ static void devm_mfd_dev_release(struct device *dev, void *res)
* Returns 0 on success or an appropriate negative error number on failure. * Returns 0 on success or an appropriate negative error number on failure.
* All child-devices of the MFD will automatically be removed when it gets * All child-devices of the MFD will automatically be removed when it gets
* unbinded. * unbinded.
*
* @dev: Pointer to parent device.
* @id: Can be PLATFORM_DEVID_AUTO to let the Platform API take care
* of device numbering, or will be added to a device's cell_id.
* @cells: Array of (struct mfd_cell)s describing child devices.
* @n_devs: Number of child devices to register.
* @mem_base: Parent register range resource for child devices.
* @irq_base: Base of the range of virtual interrupt numbers allocated for
* this MFD device. Unused if @domain is specified.
* @domain: Interrupt domain to create mappings for hardware interrupts.
*/ */
int devm_mfd_add_devices(struct device *dev, int id, int devm_mfd_add_devices(struct device *dev, int id,
const struct mfd_cell *cells, int n_devs, const struct mfd_cell *cells, int n_devs,
......
...@@ -214,6 +214,28 @@ static const struct regmap_config cpcap_regmap_config = { ...@@ -214,6 +214,28 @@ static const struct regmap_config cpcap_regmap_config = {
.val_format_endian = REGMAP_ENDIAN_LITTLE, .val_format_endian = REGMAP_ENDIAN_LITTLE,
}; };
#ifdef CONFIG_PM_SLEEP
static int cpcap_suspend(struct device *dev)
{
struct spi_device *spi = to_spi_device(dev);
disable_irq(spi->irq);
return 0;
}
static int cpcap_resume(struct device *dev)
{
struct spi_device *spi = to_spi_device(dev);
enable_irq(spi->irq);
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(cpcap_pm, cpcap_suspend, cpcap_resume);
static const struct mfd_cell cpcap_mfd_devices[] = { static const struct mfd_cell cpcap_mfd_devices[] = {
{ {
.name = "cpcap_adc", .name = "cpcap_adc",
...@@ -313,6 +335,7 @@ static struct spi_driver cpcap_driver = { ...@@ -313,6 +335,7 @@ static struct spi_driver cpcap_driver = {
.driver = { .driver = {
.name = "cpcap-core", .name = "cpcap-core",
.of_match_table = cpcap_of_match, .of_match_table = cpcap_of_match,
.pm = &cpcap_pm,
}, },
.probe = cpcap_probe, .probe = cpcap_probe,
}; };
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
/** /**
* omap-usb-host.c - The USBHS core driver for OMAP EHCI & OHCI * omap-usb-host.c - The USBHS core driver for OMAP EHCI & OHCI
* *
* Copyright (C) 2011-2013 Texas Instruments Incorporated - http://www.ti.com * Copyright (C) 2011-2013 Texas Instruments Incorporated - https://www.ti.com
* Author: Keshava Munegowda <keshava_mgowda@ti.com> * Author: Keshava Munegowda <keshava_mgowda@ti.com>
* Author: Roger Quadros <rogerq@ti.com> * Author: Roger Quadros <rogerq@ti.com>
*/ */
...@@ -120,7 +120,7 @@ static inline u32 usbhs_read(void __iomem *base, u32 reg) ...@@ -120,7 +120,7 @@ static inline u32 usbhs_read(void __iomem *base, u32 reg)
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
/** /*
* Map 'enum usbhs_omap_port_mode' found in <linux/platform_data/usb-omap.h> * Map 'enum usbhs_omap_port_mode' found in <linux/platform_data/usb-omap.h>
* to the device tree binding portN-mode found in * to the device tree binding portN-mode found in
* 'Documentation/devicetree/bindings/mfd/omap-usb-host.txt' * 'Documentation/devicetree/bindings/mfd/omap-usb-host.txt'
...@@ -526,6 +526,8 @@ static const struct of_device_id usbhs_child_match_table[] = { ...@@ -526,6 +526,8 @@ static const struct of_device_id usbhs_child_match_table[] = {
* usbhs_omap_probe - initialize TI-based HCDs * usbhs_omap_probe - initialize TI-based HCDs
* *
* Allocates basic resources for this USB host controller. * Allocates basic resources for this USB host controller.
*
* @pdev: Pointer to this device's platform device structure
*/ */
static int usbhs_omap_probe(struct platform_device *pdev) static int usbhs_omap_probe(struct platform_device *pdev)
{ {
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
/** /**
* omap-usb-tll.c - The USB TLL driver for OMAP EHCI & OHCI * omap-usb-tll.c - The USB TLL driver for OMAP EHCI & OHCI
* *
* Copyright (C) 2012-2013 Texas Instruments Incorporated - http://www.ti.com * Copyright (C) 2012-2013 Texas Instruments Incorporated - https://www.ti.com
* Author: Keshava Munegowda <keshava_mgowda@ti.com> * Author: Keshava Munegowda <keshava_mgowda@ti.com>
* Author: Roger Quadros <rogerq@ti.com> * Author: Roger Quadros <rogerq@ti.com>
*/ */
...@@ -199,6 +199,8 @@ static unsigned ohci_omap3_fslsmode(enum usbhs_omap_port_mode mode) ...@@ -199,6 +199,8 @@ static unsigned ohci_omap3_fslsmode(enum usbhs_omap_port_mode mode)
* usbtll_omap_probe - initialize TI-based HCDs * usbtll_omap_probe - initialize TI-based HCDs
* *
* Allocates basic resources for this USB host controller. * Allocates basic resources for this USB host controller.
*
* @pdev: Pointer to this device's platform device structure
*/ */
static int usbtll_omap_probe(struct platform_device *pdev) static int usbtll_omap_probe(struct platform_device *pdev)
{ {
......
...@@ -96,7 +96,7 @@ struct rave_sp_deframer { ...@@ -96,7 +96,7 @@ struct rave_sp_deframer {
* @data: Buffer to store reply payload in * @data: Buffer to store reply payload in
* @code: Expected reply code * @code: Expected reply code
* @ackid: Expected reply ACK ID * @ackid: Expected reply ACK ID
* @completion: Successful reply reception completion * @received: Successful reply reception completion
*/ */
struct rave_sp_reply { struct rave_sp_reply {
size_t length; size_t length;
......
...@@ -44,6 +44,9 @@ static bool rn5t618_volatile_reg(struct device *dev, unsigned int reg) ...@@ -44,6 +44,9 @@ static bool rn5t618_volatile_reg(struct device *dev, unsigned int reg)
case RN5T618_INTMON: case RN5T618_INTMON:
case RN5T618_RTC_CTRL1 ... RN5T618_RTC_CTRL2: case RN5T618_RTC_CTRL1 ... RN5T618_RTC_CTRL2:
case RN5T618_RTC_SECONDS ... RN5T618_RTC_YEAR: case RN5T618_RTC_SECONDS ... RN5T618_RTC_YEAR:
case RN5T618_CHGSTATE:
case RN5T618_CHGCTRL_IRR ... RN5T618_CHGERR_MONI:
case RN5T618_CONTROL ... RN5T618_CC_AVEREG0:
return true; return true;
default: default:
return false; return false;
...@@ -77,7 +80,7 @@ static const struct regmap_irq_chip rc5t619_irq_chip = { ...@@ -77,7 +80,7 @@ static const struct regmap_irq_chip rc5t619_irq_chip = {
.mask_invert = true, .mask_invert = true,
}; };
static struct rn5t618 *rn5t618_pm_power_off; static struct i2c_client *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) static int rn5t618_irq_init(struct rn5t618 *rn5t618)
...@@ -110,13 +113,38 @@ static int rn5t618_irq_init(struct rn5t618 *rn5t618) ...@@ -110,13 +113,38 @@ static int rn5t618_irq_init(struct rn5t618 *rn5t618)
static void rn5t618_trigger_poweroff_sequence(bool repower) static void rn5t618_trigger_poweroff_sequence(bool repower)
{ {
int ret;
/* disable automatic repower-on */ /* disable automatic repower-on */
regmap_update_bits(rn5t618_pm_power_off->regmap, RN5T618_REPCNT, ret = i2c_smbus_read_byte_data(rn5t618_pm_power_off, RN5T618_REPCNT);
RN5T618_REPCNT_REPWRON, if (ret < 0)
repower ? RN5T618_REPCNT_REPWRON : 0); goto err;
ret &= ~RN5T618_REPCNT_REPWRON;
if (repower)
ret |= RN5T618_REPCNT_REPWRON;
ret = i2c_smbus_write_byte_data(rn5t618_pm_power_off,
RN5T618_REPCNT, (u8)ret);
if (ret < 0)
goto err;
/* start power-off sequence */ /* start power-off sequence */
regmap_update_bits(rn5t618_pm_power_off->regmap, RN5T618_SLPCNT, ret = i2c_smbus_read_byte_data(rn5t618_pm_power_off, RN5T618_SLPCNT);
RN5T618_SLPCNT_SWPWROFF, RN5T618_SLPCNT_SWPWROFF); if (ret < 0)
goto err;
ret |= RN5T618_SLPCNT_SWPWROFF;
ret = i2c_smbus_write_byte_data(rn5t618_pm_power_off,
RN5T618_SLPCNT, (u8)ret);
if (ret < 0)
goto err;
return;
err:
dev_alert(&rn5t618_pm_power_off->dev, "Failed to shutdown (err = %d)\n", ret);
} }
static void rn5t618_power_off(void) static void rn5t618_power_off(void)
...@@ -189,7 +217,7 @@ static int rn5t618_i2c_probe(struct i2c_client *i2c) ...@@ -189,7 +217,7 @@ static int rn5t618_i2c_probe(struct i2c_client *i2c)
return ret; return ret;
} }
rn5t618_pm_power_off = priv; rn5t618_pm_power_off = i2c;
if (of_device_is_system_power_controller(i2c->dev.of_node)) { if (of_device_is_system_power_controller(i2c->dev.of_node)) {
if (!pm_power_off) if (!pm_power_off)
pm_power_off = rn5t618_power_off; pm_power_off = rn5t618_power_off;
...@@ -211,9 +239,7 @@ static int rn5t618_i2c_probe(struct i2c_client *i2c) ...@@ -211,9 +239,7 @@ static int rn5t618_i2c_probe(struct i2c_client *i2c)
static int rn5t618_i2c_remove(struct i2c_client *i2c) static int rn5t618_i2c_remove(struct i2c_client *i2c)
{ {
struct rn5t618 *priv = i2c_get_clientdata(i2c); if (i2c == rn5t618_pm_power_off) {
if (priv == rn5t618_pm_power_off) {
rn5t618_pm_power_off = NULL; rn5t618_pm_power_off = NULL;
pm_power_off = NULL; pm_power_off = NULL;
} }
......
...@@ -241,13 +241,13 @@ static int si476x_core_parse_and_nag_about_error(struct si476x_core *core) ...@@ -241,13 +241,13 @@ static int si476x_core_parse_and_nag_about_error(struct si476x_core *core)
/** /**
* si476x_core_send_command() - sends a command to si476x and waits its * si476x_core_send_command() - sends a command to si476x and waits its
* response * response
* @core: si476x_device structure for the device we are * @core: si476x_device structure for the device we are
* communicating with * communicating with
* @command: command id * @command: command id
* @args: command arguments we are sending * @args: command arguments we are sending
* @argn: actual size of @args * @argn: actual size of @args
* @response: buffer to place the expected response from the device * @resp: buffer to place the expected response from the device
* @respn: actual size of @response * @respn: actual size of @resp
* @usecs: amount of time to wait before reading the response (in * @usecs: amount of time to wait before reading the response (in
* usecs) * usecs)
* *
...@@ -496,7 +496,7 @@ EXPORT_SYMBOL_GPL(si476x_core_cmd_get_property); ...@@ -496,7 +496,7 @@ EXPORT_SYMBOL_GPL(si476x_core_cmd_get_property);
* enable 1MOhm pulldown * enable 1MOhm pulldown
* SI476X_DFS_DAUDIO - set the pin to be a part of digital * SI476X_DFS_DAUDIO - set the pin to be a part of digital
* audio interface * audio interface
* @dout - DOUT pin function configuration: * @dout: - DOUT pin function configuration:
* SI476X_DOUT_NOOP - do not modify the behaviour * SI476X_DOUT_NOOP - do not modify the behaviour
* SI476X_DOUT_TRISTATE - put the pin in tristate condition, * SI476X_DOUT_TRISTATE - put the pin in tristate condition,
* enable 1MOhm pulldown * enable 1MOhm pulldown
...@@ -504,7 +504,7 @@ EXPORT_SYMBOL_GPL(si476x_core_cmd_get_property); ...@@ -504,7 +504,7 @@ EXPORT_SYMBOL_GPL(si476x_core_cmd_get_property);
* port 1 * port 1
* SI476X_DOUT_I2S_INPUT - set this pin to be digital in on I2S * SI476X_DOUT_I2S_INPUT - set this pin to be digital in on I2S
* port 1 * port 1
* @xout - XOUT pin function configuration: * @xout: - XOUT pin function configuration:
* SI476X_XOUT_NOOP - do not modify the behaviour * SI476X_XOUT_NOOP - do not modify the behaviour
* SI476X_XOUT_TRISTATE - put the pin in tristate condition, * SI476X_XOUT_TRISTATE - put the pin in tristate condition,
* enable 1MOhm pulldown * enable 1MOhm pulldown
...@@ -540,25 +540,25 @@ EXPORT_SYMBOL_GPL(si476x_core_cmd_dig_audio_pin_cfg); ...@@ -540,25 +540,25 @@ EXPORT_SYMBOL_GPL(si476x_core_cmd_dig_audio_pin_cfg);
/** /**
* si476x_cmd_zif_pin_cfg - send 'ZIF_PIN_CFG_COMMAND' * si476x_cmd_zif_pin_cfg - send 'ZIF_PIN_CFG_COMMAND'
* @core - device to send the command to * @core: - device to send the command to
* @iqclk - IQCL pin function configuration: * @iqclk: - IQCL pin function configuration:
* SI476X_IQCLK_NOOP - do not modify the behaviour * SI476X_IQCLK_NOOP - do not modify the behaviour
* SI476X_IQCLK_TRISTATE - put the pin in tristate condition, * SI476X_IQCLK_TRISTATE - put the pin in tristate condition,
* enable 1MOhm pulldown * enable 1MOhm pulldown
* SI476X_IQCLK_IQ - set pin to be a part of I/Q interace * SI476X_IQCLK_IQ - set pin to be a part of I/Q interace
* in master mode * in master mode
* @iqfs - IQFS pin function configuration: * @iqfs: - IQFS pin function configuration:
* SI476X_IQFS_NOOP - do not modify the behaviour * SI476X_IQFS_NOOP - do not modify the behaviour
* SI476X_IQFS_TRISTATE - put the pin in tristate condition, * SI476X_IQFS_TRISTATE - put the pin in tristate condition,
* enable 1MOhm pulldown * enable 1MOhm pulldown
* SI476X_IQFS_IQ - set pin to be a part of I/Q interace * SI476X_IQFS_IQ - set pin to be a part of I/Q interace
* in master mode * in master mode
* @iout - IOUT pin function configuration: * @iout: - IOUT pin function configuration:
* SI476X_IOUT_NOOP - do not modify the behaviour * SI476X_IOUT_NOOP - do not modify the behaviour
* SI476X_IOUT_TRISTATE - put the pin in tristate condition, * SI476X_IOUT_TRISTATE - put the pin in tristate condition,
* enable 1MOhm pulldown * enable 1MOhm pulldown
* SI476X_IOUT_OUTPUT - set pin to be I out * SI476X_IOUT_OUTPUT - set pin to be I out
* @qout - QOUT pin function configuration: * @qout: - QOUT pin function configuration:
* SI476X_QOUT_NOOP - do not modify the behaviour * SI476X_QOUT_NOOP - do not modify the behaviour
* SI476X_QOUT_TRISTATE - put the pin in tristate condition, * SI476X_QOUT_TRISTATE - put the pin in tristate condition,
* enable 1MOhm pulldown * enable 1MOhm pulldown
...@@ -590,29 +590,29 @@ EXPORT_SYMBOL_GPL(si476x_core_cmd_zif_pin_cfg); ...@@ -590,29 +590,29 @@ EXPORT_SYMBOL_GPL(si476x_core_cmd_zif_pin_cfg);
/** /**
* si476x_cmd_ic_link_gpo_ctl_pin_cfg - send * si476x_cmd_ic_link_gpo_ctl_pin_cfg - send
* 'IC_LINK_GPIO_CTL_PIN_CFG' comand to the device * 'IC_LINK_GPIO_CTL_PIN_CFG' comand to the device
* @core - device to send the command to * @core: - device to send the command to
* @icin - ICIN pin function configuration: * @icin: - ICIN pin function configuration:
* SI476X_ICIN_NOOP - do not modify the behaviour * SI476X_ICIN_NOOP - do not modify the behaviour
* SI476X_ICIN_TRISTATE - put the pin in tristate condition, * SI476X_ICIN_TRISTATE - put the pin in tristate condition,
* enable 1MOhm pulldown * enable 1MOhm pulldown
* SI476X_ICIN_GPO1_HIGH - set pin to be an output, drive it high * SI476X_ICIN_GPO1_HIGH - set pin to be an output, drive it high
* SI476X_ICIN_GPO1_LOW - set pin to be an output, drive it low * SI476X_ICIN_GPO1_LOW - set pin to be an output, drive it low
* SI476X_ICIN_IC_LINK - set the pin to be a part of Inter-Chip link * SI476X_ICIN_IC_LINK - set the pin to be a part of Inter-Chip link
* @icip - ICIP pin function configuration: * @icip: - ICIP pin function configuration:
* SI476X_ICIP_NOOP - do not modify the behaviour * SI476X_ICIP_NOOP - do not modify the behaviour
* SI476X_ICIP_TRISTATE - put the pin in tristate condition, * SI476X_ICIP_TRISTATE - put the pin in tristate condition,
* enable 1MOhm pulldown * enable 1MOhm pulldown
* SI476X_ICIP_GPO1_HIGH - set pin to be an output, drive it high * SI476X_ICIP_GPO1_HIGH - set pin to be an output, drive it high
* SI476X_ICIP_GPO1_LOW - set pin to be an output, drive it low * SI476X_ICIP_GPO1_LOW - set pin to be an output, drive it low
* SI476X_ICIP_IC_LINK - set the pin to be a part of Inter-Chip link * SI476X_ICIP_IC_LINK - set the pin to be a part of Inter-Chip link
* @icon - ICON pin function configuration: * @icon: - ICON pin function configuration:
* SI476X_ICON_NOOP - do not modify the behaviour * SI476X_ICON_NOOP - do not modify the behaviour
* SI476X_ICON_TRISTATE - put the pin in tristate condition, * SI476X_ICON_TRISTATE - put the pin in tristate condition,
* enable 1MOhm pulldown * enable 1MOhm pulldown
* SI476X_ICON_I2S - set the pin to be a part of audio * SI476X_ICON_I2S - set the pin to be a part of audio
* interface in slave mode (DCLK) * interface in slave mode (DCLK)
* SI476X_ICON_IC_LINK - set the pin to be a part of Inter-Chip link * SI476X_ICON_IC_LINK - set the pin to be a part of Inter-Chip link
* @icop - ICOP pin function configuration: * @icop: - ICOP pin function configuration:
* SI476X_ICOP_NOOP - do not modify the behaviour * SI476X_ICOP_NOOP - do not modify the behaviour
* SI476X_ICOP_TRISTATE - put the pin in tristate condition, * SI476X_ICOP_TRISTATE - put the pin in tristate condition,
* enable 1MOhm pulldown * enable 1MOhm pulldown
...@@ -647,8 +647,8 @@ EXPORT_SYMBOL_GPL(si476x_core_cmd_ic_link_gpo_ctl_pin_cfg); ...@@ -647,8 +647,8 @@ EXPORT_SYMBOL_GPL(si476x_core_cmd_ic_link_gpo_ctl_pin_cfg);
/** /**
* si476x_cmd_ana_audio_pin_cfg - send 'ANA_AUDIO_PIN_CFG' to the * si476x_cmd_ana_audio_pin_cfg - send 'ANA_AUDIO_PIN_CFG' to the
* device * device
* @core - device to send the command to * @core: - device to send the command to
* @lrout - LROUT pin function configuration: * @lrout: - LROUT pin function configuration:
* SI476X_LROUT_NOOP - do not modify the behaviour * SI476X_LROUT_NOOP - do not modify the behaviour
* SI476X_LROUT_TRISTATE - put the pin in tristate condition, * SI476X_LROUT_TRISTATE - put the pin in tristate condition,
* enable 1MOhm pulldown * enable 1MOhm pulldown
...@@ -675,15 +675,15 @@ EXPORT_SYMBOL_GPL(si476x_core_cmd_ana_audio_pin_cfg); ...@@ -675,15 +675,15 @@ EXPORT_SYMBOL_GPL(si476x_core_cmd_ana_audio_pin_cfg);
/** /**
* si476x_cmd_intb_pin_cfg - send 'INTB_PIN_CFG' command to the device * si476x_cmd_intb_pin_cfg - send 'INTB_PIN_CFG' command to the device
* @core - device to send the command to * @core: - device to send the command to
* @intb - INTB pin function configuration: * @intb: - INTB pin function configuration:
* SI476X_INTB_NOOP - do not modify the behaviour * SI476X_INTB_NOOP - do not modify the behaviour
* SI476X_INTB_TRISTATE - put the pin in tristate condition, * SI476X_INTB_TRISTATE - put the pin in tristate condition,
* enable 1MOhm pulldown * enable 1MOhm pulldown
* SI476X_INTB_DAUDIO - set pin to be a part of digital * SI476X_INTB_DAUDIO - set pin to be a part of digital
* audio interface in slave mode * audio interface in slave mode
* SI476X_INTB_IRQ - set pin to be an interrupt request line * SI476X_INTB_IRQ - set pin to be an interrupt request line
* @a1 - A1 pin function configuration: * @a1: - A1 pin function configuration:
* SI476X_A1_NOOP - do not modify the behaviour * SI476X_A1_NOOP - do not modify the behaviour
* SI476X_A1_TRISTATE - put the pin in tristate condition, * SI476X_A1_TRISTATE - put the pin in tristate condition,
* enable 1MOhm pulldown * enable 1MOhm pulldown
...@@ -728,14 +728,10 @@ static int si476x_core_cmd_intb_pin_cfg_a20(struct si476x_core *core, ...@@ -728,14 +728,10 @@ static int si476x_core_cmd_intb_pin_cfg_a20(struct si476x_core *core,
/** /**
* si476x_cmd_am_rsq_status - send 'AM_RSQ_STATUS' command to the * si476x_cmd_am_rsq_status - send 'AM_RSQ_STATUS' command to the
* device * device
* @core - device to send the command to * @core: - device to send the command to
* @rsqack - if set command clears RSQINT, SNRINT, SNRLINT, RSSIHINT, * @rsqargs: - pointer to a structure containing a group of sub-args
* RSSSILINT, BLENDINT, MULTHINT and MULTLINT * relevant to sending the RSQ status command
* @attune - when set the values in the status report are the values * @report: - all signal quality information retured by the command
* that were calculated at tune
* @cancel - abort ongoing seek/tune opertation
* @stcack - clear the STCINT bin in status register
* @report - all signal quality information retured by the command
* (if NULL then the output of the command is ignored) * (if NULL then the output of the command is ignored)
* *
* Function returns 0 on success and negative error code on failure * Function returns 0 on success and negative error code on failure
...@@ -862,9 +858,9 @@ EXPORT_SYMBOL_GPL(si476x_core_cmd_am_acf_status); ...@@ -862,9 +858,9 @@ EXPORT_SYMBOL_GPL(si476x_core_cmd_am_acf_status);
/** /**
* si476x_cmd_fm_seek_start - send 'FM_SEEK_START' command to the * si476x_cmd_fm_seek_start - send 'FM_SEEK_START' command to the
* device * device
* @core - device to send the command to * @core: - device to send the command to
* @seekup - if set the direction of the search is 'up' * @seekup: - if set the direction of the search is 'up'
* @wrap - if set seek wraps when hitting band limit * @wrap: - if set seek wraps when hitting band limit
* *
* This function begins search for a valid station. The station is * This function begins search for a valid station. The station is
* considered valid when 'FM_VALID_SNR_THRESHOLD' and * considered valid when 'FM_VALID_SNR_THRESHOLD' and
...@@ -890,12 +886,14 @@ EXPORT_SYMBOL_GPL(si476x_core_cmd_fm_seek_start); ...@@ -890,12 +886,14 @@ EXPORT_SYMBOL_GPL(si476x_core_cmd_fm_seek_start);
/** /**
* si476x_cmd_fm_rds_status - send 'FM_RDS_STATUS' command to the * si476x_cmd_fm_rds_status - send 'FM_RDS_STATUS' command to the
* device * device
* @core - device to send the command to * @core: - device to send the command to
* @status_only - if set the data is not removed from RDSFIFO, * @status_only: - if set the data is not removed from RDSFIFO,
* RDSFIFOUSED is not decremented and data in all the * RDSFIFOUSED is not decremented and data in all the
* rest RDS data contains the last valid info received * rest RDS data contains the last valid info received
* @mtfifo if set the command clears RDS receive FIFO * @mtfifo: if set the command clears RDS receive FIFO
* @intack if set the command clards the RDSINT bit. * @intack: if set the command clards the RDSINT bit.
* @report: - all signal quality information retured by the command
* (if NULL then the output of the command is ignored)
* *
* Function returns 0 on success and negative error code on failure * Function returns 0 on success and negative error code on failure
*/ */
...@@ -1036,9 +1034,9 @@ EXPORT_SYMBOL_GPL(si476x_core_cmd_fm_phase_div_status); ...@@ -1036,9 +1034,9 @@ EXPORT_SYMBOL_GPL(si476x_core_cmd_fm_phase_div_status);
/** /**
* si476x_cmd_am_seek_start - send 'FM_SEEK_START' command to the * si476x_cmd_am_seek_start - send 'FM_SEEK_START' command to the
* device * device
* @core - device to send the command to * @core: - device to send the command to
* @seekup - if set the direction of the search is 'up' * @seekup: - if set the direction of the search is 'up'
* @wrap - if set seek wraps when hitting band limit * @wrap: - if set seek wraps when hitting band limit
* *
* This function begins search for a valid station. The station is * This function begins search for a valid station. The station is
* considered valid when 'FM_VALID_SNR_THRESHOLD' and * considered valid when 'FM_VALID_SNR_THRESHOLD' and
......
...@@ -534,6 +534,11 @@ static irqreturn_t si476x_core_interrupt(int irq, void *dev) ...@@ -534,6 +534,11 @@ static irqreturn_t si476x_core_interrupt(int irq, void *dev)
/** /**
* si476x_firmware_version_to_revision() * si476x_firmware_version_to_revision()
* @core: Core device structure * @core: Core device structure
* @func: Selects the boot function of the device:
* *_BOOTLOADER - Boot loader
* *_FM_RECEIVER - FM receiver
* *_AM_RECEIVER - AM receiver
* *_WB_RECEIVER - Weatherband receiver
* @major: Firmware major number * @major: Firmware major number
* @minor1: Firmware first minor number * @minor1: Firmware first minor number
* @minor2: Firmware second minor number * @minor2: Firmware second minor number
...@@ -583,7 +588,7 @@ static int si476x_core_fwver_to_revision(struct si476x_core *core, ...@@ -583,7 +588,7 @@ static int si476x_core_fwver_to_revision(struct si476x_core *core,
goto unknown_revision; goto unknown_revision;
} }
case SI476X_FUNC_BOOTLOADER: case SI476X_FUNC_BOOTLOADER:
default: /* FALLTHROUG */ default: /* FALLTHROUGH */
BUG(); BUG();
return -1; return -1;
} }
......
/*
* TI SMSC MFD Driver
*
* Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com
*
* Author: Sourav Poddar <sourav.poddar@ti.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; GPL v2.
*
*/
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/gpio.h>
#include <linux/workqueue.h>
#include <linux/irq.h>
#include <linux/regmap.h>
#include <linux/err.h>
#include <linux/mfd/core.h>
#include <linux/mfd/smsc.h>
#include <linux/of_platform.h>
static const struct regmap_config smsc_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = SMSC_VEN_ID_H,
.cache_type = REGCACHE_RBTREE,
};
static int smsc_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct smsc *smsc;
int devid, rev, venid_l, venid_h;
int ret;
smsc = devm_kzalloc(&i2c->dev, sizeof(*smsc), GFP_KERNEL);
if (!smsc)
return -ENOMEM;
smsc->regmap = devm_regmap_init_i2c(i2c, &smsc_regmap_config);
if (IS_ERR(smsc->regmap))
return PTR_ERR(smsc->regmap);
i2c_set_clientdata(i2c, smsc);
smsc->dev = &i2c->dev;
#ifdef CONFIG_OF
of_property_read_u32(i2c->dev.of_node, "clock", &smsc->clk);
#endif
regmap_read(smsc->regmap, SMSC_DEV_ID, &devid);
regmap_read(smsc->regmap, SMSC_DEV_REV, &rev);
regmap_read(smsc->regmap, SMSC_VEN_ID_L, &venid_l);
regmap_read(smsc->regmap, SMSC_VEN_ID_H, &venid_h);
dev_info(&i2c->dev, "SMSCxxx devid: %02x rev: %02x venid: %02x\n",
devid, rev, (venid_h << 8) | venid_l);
ret = regmap_write(smsc->regmap, SMSC_CLK_CTRL, smsc->clk);
if (ret)
return ret;
#ifdef CONFIG_OF
if (i2c->dev.of_node)
ret = devm_of_platform_populate(&i2c->dev);
#endif
return ret;
}
static const struct i2c_device_id smsc_i2c_id[] = {
{ "smscece1099", 0},
{},
};
static struct i2c_driver smsc_i2c_driver = {
.driver = {
.name = "smsc",
},
.probe = smsc_i2c_probe,
.id_table = smsc_i2c_id,
};
builtin_i2c_driver(smsc_i2c_driver);
...@@ -7,7 +7,9 @@ ...@@ -7,7 +7,9 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/mfd/core.h> #include <linux/mfd/core.h>
#include <linux/mfd/sc27xx-pmic.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/of_platform.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> #include <uapi/linux/usb/charger.h>
...@@ -93,73 +95,6 @@ enum usb_charger_type sprd_pmic_detect_charger_type(struct device *dev) ...@@ -93,73 +95,6 @@ enum usb_charger_type sprd_pmic_detect_charger_type(struct device *dev)
} }
EXPORT_SYMBOL_GPL(sprd_pmic_detect_charger_type); EXPORT_SYMBOL_GPL(sprd_pmic_detect_charger_type);
static const struct mfd_cell sprd_pmic_devs[] = {
{
.name = "sc27xx-wdt",
.of_compatible = "sprd,sc2731-wdt",
}, {
.name = "sc27xx-rtc",
.of_compatible = "sprd,sc2731-rtc",
}, {
.name = "sc27xx-charger",
.of_compatible = "sprd,sc2731-charger",
}, {
.name = "sc27xx-chg-timer",
.of_compatible = "sprd,sc2731-chg-timer",
}, {
.name = "sc27xx-fast-chg",
.of_compatible = "sprd,sc2731-fast-chg",
}, {
.name = "sc27xx-chg-wdt",
.of_compatible = "sprd,sc2731-chg-wdt",
}, {
.name = "sc27xx-typec",
.of_compatible = "sprd,sc2731-typec",
}, {
.name = "sc27xx-flash",
.of_compatible = "sprd,sc2731-flash",
}, {
.name = "sc27xx-eic",
.of_compatible = "sprd,sc2731-eic",
}, {
.name = "sc27xx-efuse",
.of_compatible = "sprd,sc2731-efuse",
}, {
.name = "sc27xx-thermal",
.of_compatible = "sprd,sc2731-thermal",
}, {
.name = "sc27xx-adc",
.of_compatible = "sprd,sc2731-adc",
}, {
.name = "sc27xx-audio-codec",
.of_compatible = "sprd,sc2731-audio-codec",
}, {
.name = "sc27xx-regulator",
.of_compatible = "sprd,sc2731-regulator",
}, {
.name = "sc27xx-vibrator",
.of_compatible = "sprd,sc2731-vibrator",
}, {
.name = "sc27xx-keypad-led",
.of_compatible = "sprd,sc2731-keypad-led",
}, {
.name = "sc27xx-bltc",
.of_compatible = "sprd,sc2731-bltc",
}, {
.name = "sc27xx-fgu",
.of_compatible = "sprd,sc2731-fgu",
}, {
.name = "sc27xx-7sreset",
.of_compatible = "sprd,sc2731-7sreset",
}, {
.name = "sc27xx-poweroff",
.of_compatible = "sprd,sc2731-poweroff",
}, {
.name = "sc27xx-syscon",
.of_compatible = "sprd,sc2731-syscon",
},
};
static int sprd_pmic_spi_write(void *context, const void *data, size_t count) static int sprd_pmic_spi_write(void *context, const void *data, size_t count)
{ {
struct device *dev = context; struct device *dev = context;
...@@ -250,10 +185,8 @@ static int sprd_pmic_probe(struct spi_device *spi) ...@@ -250,10 +185,8 @@ static int sprd_pmic_probe(struct spi_device *spi)
return -ENOMEM; return -ENOMEM;
ddata->irq_chip.irqs = ddata->irqs; ddata->irq_chip.irqs = ddata->irqs;
for (i = 0; i < pdata->num_irqs; i++) { for (i = 0; i < pdata->num_irqs; i++)
ddata->irqs[i].reg_offset = i / pdata->num_irqs; ddata->irqs[i].mask = BIT(i);
ddata->irqs[i].mask = BIT(i % pdata->num_irqs);
}
ret = devm_regmap_add_irq_chip(&spi->dev, ddata->regmap, ddata->irq, ret = devm_regmap_add_irq_chip(&spi->dev, ddata->regmap, ddata->irq,
IRQF_ONESHOT | IRQF_NO_SUSPEND, 0, IRQF_ONESHOT | IRQF_NO_SUSPEND, 0,
...@@ -263,12 +196,9 @@ static int sprd_pmic_probe(struct spi_device *spi) ...@@ -263,12 +196,9 @@ static int sprd_pmic_probe(struct spi_device *spi)
return ret; return ret;
} }
ret = devm_mfd_add_devices(&spi->dev, PLATFORM_DEVID_AUTO, ret = devm_of_platform_populate(&spi->dev);
sprd_pmic_devs, ARRAY_SIZE(sprd_pmic_devs),
NULL, 0,
regmap_irq_get_domain(ddata->irq_data));
if (ret) { if (ret) {
dev_err(&spi->dev, "Failed to register device %d\n", ret); dev_err(&spi->dev, "Failed to populate sub-devices %d\n", ret);
return ret; return ret;
} }
......
...@@ -17,6 +17,7 @@ static const struct regmap_config stm32_lptimer_regmap_cfg = { ...@@ -17,6 +17,7 @@ static const struct regmap_config stm32_lptimer_regmap_cfg = {
.val_bits = 32, .val_bits = 32,
.reg_stride = sizeof(u32), .reg_stride = sizeof(u32),
.max_register = STM32_LPTIM_MAX_REGISTER, .max_register = STM32_LPTIM_MAX_REGISTER,
.fast_io = true,
}; };
static int stm32_lptimer_detect_encoder(struct stm32_lptimer *ddata) static int stm32_lptimer_detect_encoder(struct stm32_lptimer *ddata)
......
...@@ -101,12 +101,14 @@ static struct syscon *of_syscon_register(struct device_node *np, bool check_clk) ...@@ -101,12 +101,14 @@ static struct syscon *of_syscon_register(struct device_node *np, bool check_clk)
} }
} }
syscon_config.name = of_node_full_name(np); syscon_config.name = kasprintf(GFP_KERNEL, "%pOFn@%llx", np,
(u64)res.start);
syscon_config.reg_stride = reg_io_width; syscon_config.reg_stride = reg_io_width;
syscon_config.val_bits = reg_io_width * 8; syscon_config.val_bits = reg_io_width * 8;
syscon_config.max_register = resource_size(&res) - reg_io_width; syscon_config.max_register = resource_size(&res) - reg_io_width;
regmap = regmap_init_mmio(NULL, base, &syscon_config); regmap = regmap_init_mmio(NULL, base, &syscon_config);
kfree(syscon_config.name);
if (IS_ERR(regmap)) { if (IS_ERR(regmap)) {
pr_err("regmap init failed\n"); pr_err("regmap init failed\n");
ret = PTR_ERR(regmap); ret = PTR_ERR(regmap);
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
#include <linux/mfd/tc3589x.h> #include <linux/mfd/tc3589x.h>
#include <linux/err.h> #include <linux/err.h>
/** /*
* enum tc3589x_version - indicates the TC3589x version * enum tc3589x_version - indicates the TC3589x version
*/ */
enum tc3589x_version { enum tc3589x_version {
......
/* /*
* TI Touch Screen / ADC MFD driver * TI Touch Screen / ADC MFD driver
* *
* Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ * Copyright (C) 2012 Texas Instruments Incorporated - https://www.ti.com/
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as * modify it under the terms of the GNU General Public License as
......
...@@ -404,7 +404,6 @@ static void tps65010_work(struct work_struct *work) ...@@ -404,7 +404,6 @@ static void tps65010_work(struct work_struct *work)
tps65010_interrupt(tps); tps65010_interrupt(tps);
if (test_and_clear_bit(FLAG_VBUS_CHANGED, &tps->flags)) { if (test_and_clear_bit(FLAG_VBUS_CHANGED, &tps->flags)) {
int status;
u8 chgconfig, tmp; u8 chgconfig, tmp;
chgconfig = i2c_smbus_read_byte_data(tps->client, chgconfig = i2c_smbus_read_byte_data(tps->client,
...@@ -415,8 +414,8 @@ static void tps65010_work(struct work_struct *work) ...@@ -415,8 +414,8 @@ static void tps65010_work(struct work_struct *work)
else if (tps->vbus >= 100) else if (tps->vbus >= 100)
chgconfig |= TPS_VBUS_CHARGING; chgconfig |= TPS_VBUS_CHARGING;
status = i2c_smbus_write_byte_data(tps->client, i2c_smbus_write_byte_data(tps->client,
TPS_CHGCONFIG, chgconfig); TPS_CHGCONFIG, chgconfig);
/* vbus update fails unless VBUS is connected! */ /* vbus update fails unless VBUS is connected! */
tmp = i2c_smbus_read_byte_data(tps->client, TPS_CHGCONFIG); tmp = i2c_smbus_read_byte_data(tps->client, TPS_CHGCONFIG);
......
/* /*
* Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/ * Copyright (C) 2015 Texas Instruments Incorporated - https://www.ti.com/
* Andrew F. Davis <afd@ti.com> * Andrew F. Davis <afd@ti.com>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* *
* TPS65217 chip family multi-function driver * TPS65217 chip family multi-function driver
* *
* Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ * Copyright (C) 2011 Texas Instruments Incorporated - https://www.ti.com/
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as * modify it under the terms of the GNU General Public License as
...@@ -205,7 +205,7 @@ EXPORT_SYMBOL_GPL(tps65217_reg_read); ...@@ -205,7 +205,7 @@ EXPORT_SYMBOL_GPL(tps65217_reg_read);
/** /**
* tps65217_reg_write: Write a single tps65217 register. * tps65217_reg_write: Write a single tps65217 register.
* *
* @tps65217: Device to write to. * @tps: Device to write to.
* @reg: Register to write to. * @reg: Register to write to.
* @val: Value to write. * @val: Value to write.
* @level: Password protected level * @level: Password protected level
...@@ -250,7 +250,7 @@ EXPORT_SYMBOL_GPL(tps65217_reg_write); ...@@ -250,7 +250,7 @@ EXPORT_SYMBOL_GPL(tps65217_reg_write);
/** /**
* tps65217_update_bits: Modify bits w.r.t mask, val and level. * tps65217_update_bits: Modify bits w.r.t mask, val and level.
* *
* @tps65217: Device to write to. * @tps: Device to write to.
* @reg: Register to read-write to. * @reg: Register to read-write to.
* @mask: Mask. * @mask: Mask.
* @val: Value to write. * @val: Value to write.
......
/* /*
* Driver for TPS65218 Integrated power management chipsets * Driver for TPS65218 Integrated power management chipsets
* *
* Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ * Copyright (C) 2014 Texas Instruments Incorporated - https://www.ti.com/
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as * modify it under the terms of the GNU General Public License version 2 as
...@@ -48,7 +48,7 @@ static const struct mfd_cell tps65218_cells[] = { ...@@ -48,7 +48,7 @@ static const struct mfd_cell tps65218_cells[] = {
/** /**
* tps65218_reg_write: Write a single tps65218 register. * tps65218_reg_write: Write a single tps65218 register.
* *
* @tps65218: Device to write to. * @tps: Device to write to.
* @reg: Register to write to. * @reg: Register to write to.
* @val: Value to write. * @val: Value to write.
* @level: Password protected level * @level: Password protected level
...@@ -79,7 +79,7 @@ EXPORT_SYMBOL_GPL(tps65218_reg_write); ...@@ -79,7 +79,7 @@ EXPORT_SYMBOL_GPL(tps65218_reg_write);
/** /**
* tps65218_update_bits: Modify bits w.r.t mask, val and level. * tps65218_update_bits: Modify bits w.r.t mask, val and level.
* *
* @tps65218: Device to write to. * @tps: Device to write to.
* @reg: Register to read-write to. * @reg: Register to read-write to.
* @mask: Mask. * @mask: Mask.
* @val: Value to write. * @val: Value to write.
......
...@@ -309,18 +309,19 @@ static const struct irq_domain_ops tps6586x_domain_ops = { ...@@ -309,18 +309,19 @@ static const struct irq_domain_ops tps6586x_domain_ops = {
static irqreturn_t tps6586x_irq(int irq, void *data) static irqreturn_t tps6586x_irq(int irq, void *data)
{ {
struct tps6586x *tps6586x = data; struct tps6586x *tps6586x = data;
u32 acks; uint32_t acks;
__le32 val;
int ret = 0; int ret = 0;
ret = tps6586x_reads(tps6586x->dev, TPS6586X_INT_ACK1, ret = tps6586x_reads(tps6586x->dev, TPS6586X_INT_ACK1,
sizeof(acks), (uint8_t *)&acks); sizeof(acks), (uint8_t *)&val);
if (ret < 0) { if (ret < 0) {
dev_err(tps6586x->dev, "failed to read interrupt status\n"); dev_err(tps6586x->dev, "failed to read interrupt status\n");
return IRQ_NONE; return IRQ_NONE;
} }
acks = le32_to_cpu(acks); acks = le32_to_cpu(val);
while (acks) { while (acks) {
int i = __ffs(acks); int i = __ffs(acks);
......
/* /*
* Core functions for TI TPS65912x PMICs * Core functions for TI TPS65912x PMICs
* *
* Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/ * Copyright (C) 2015 Texas Instruments Incorporated - https://www.ti.com/
* Andrew F. Davis <afd@ti.com> * Andrew F. Davis <afd@ti.com>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
......
/* /*
* I2C access driver for TI TPS65912x PMICs * I2C access driver for TI TPS65912x PMICs
* *
* Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/ * Copyright (C) 2015 Texas Instruments Incorporated - https://www.ti.com/
* Andrew F. Davis <afd@ti.com> * Andrew F. Davis <afd@ti.com>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
......
/* /*
* SPI access driver for TI TPS65912x PMICs * SPI access driver for TI TPS65912x PMICs
* *
* Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/ * Copyright (C) 2015 Texas Instruments Incorporated - https://www.ti.com/
* Andrew F. Davis <afd@ti.com> * Andrew F. Davis <afd@ti.com>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
......
...@@ -477,7 +477,7 @@ static void twl4030_sih_bus_sync_unlock(struct irq_data *data) ...@@ -477,7 +477,7 @@ static void twl4030_sih_bus_sync_unlock(struct irq_data *data)
if (agent->imr_change_pending) { if (agent->imr_change_pending) {
union { union {
u32 word; __le32 word;
u8 bytes[4]; u8 bytes[4];
} imr; } imr;
...@@ -561,7 +561,7 @@ static inline int sih_read_isr(const struct sih *sih) ...@@ -561,7 +561,7 @@ static inline int sih_read_isr(const struct sih *sih)
int status; int status;
union { union {
u8 bytes[4]; u8 bytes[4];
u32 word; __le32 word;
} isr; } isr;
/* FIXME need retry-on-error ... */ /* FIXME need retry-on-error ... */
......
...@@ -114,6 +114,8 @@ static int wm831x_reg_locked(struct wm831x *wm831x, unsigned short reg) ...@@ -114,6 +114,8 @@ static int wm831x_reg_locked(struct wm831x *wm831x, unsigned short reg)
* The WM831x has a user key preventing writes to particularly * The WM831x has a user key preventing writes to particularly
* critical registers. This function locks those registers, * critical registers. This function locks those registers,
* allowing writes to them. * allowing writes to them.
*
* @wm831x: pointer to local driver data structure
*/ */
void wm831x_reg_lock(struct wm831x *wm831x) void wm831x_reg_lock(struct wm831x *wm831x)
{ {
...@@ -140,6 +142,8 @@ EXPORT_SYMBOL_GPL(wm831x_reg_lock); ...@@ -140,6 +142,8 @@ EXPORT_SYMBOL_GPL(wm831x_reg_lock);
* The WM831x has a user key preventing writes to particularly * The WM831x has a user key preventing writes to particularly
* critical registers. This function locks those registers, * critical registers. This function locks those registers,
* preventing spurious writes. * preventing spurious writes.
*
* @wm831x: pointer to local driver data structure
*/ */
int wm831x_reg_unlock(struct wm831x *wm831x) int wm831x_reg_unlock(struct wm831x *wm831x)
{ {
......
...@@ -131,6 +131,8 @@ EXPORT_SYMBOL_GPL(wm8350_block_write); ...@@ -131,6 +131,8 @@ EXPORT_SYMBOL_GPL(wm8350_block_write);
* The WM8350 has a hardware lock which can be used to prevent writes to * The WM8350 has a hardware lock which can be used to prevent writes to
* some registers (generally those which can cause particularly serious * some registers (generally those which can cause particularly serious
* problems if misused). This function enables that lock. * problems if misused). This function enables that lock.
*
* @wm8350: pointer to local driver data structure
*/ */
int wm8350_reg_lock(struct wm8350 *wm8350) int wm8350_reg_lock(struct wm8350 *wm8350)
{ {
...@@ -160,6 +162,8 @@ EXPORT_SYMBOL_GPL(wm8350_reg_lock); ...@@ -160,6 +162,8 @@ EXPORT_SYMBOL_GPL(wm8350_reg_lock);
* problems if misused). This function disables that lock so updates * problems if misused). This function disables that lock so updates
* can be performed. For maximum safety this should be done only when * can be performed. For maximum safety this should be done only when
* required. * required.
*
* @wm8350: pointer to local driver data structure
*/ */
int wm8350_reg_unlock(struct wm8350 *wm8350) int wm8350_reg_unlock(struct wm8350 *wm8350)
{ {
......
...@@ -108,6 +108,8 @@ static const struct regmap_config wm8400_regmap_config = { ...@@ -108,6 +108,8 @@ static const struct regmap_config wm8400_regmap_config = {
/** /**
* wm8400_reset_codec_reg_cache - Reset cached codec registers to * wm8400_reset_codec_reg_cache - Reset cached codec registers to
* their default values. * their default values.
*
* @wm8400: pointer to local driver data structure
*/ */
void wm8400_reset_codec_reg_cache(struct wm8400 *wm8400) void wm8400_reset_codec_reg_cache(struct wm8400 *wm8400)
{ {
......
...@@ -499,4 +499,15 @@ config SPRD_THERMAL ...@@ -499,4 +499,15 @@ config SPRD_THERMAL
help help
Support for the Spreadtrum thermal sensor driver in the Linux thermal Support for the Spreadtrum thermal sensor driver in the Linux thermal
framework. framework.
config KHADAS_MCU_FAN_THERMAL
tristate "Khadas MCU controller FAN cooling support"
depends on OF || COMPILE_TEST
depends on MFD_KHADAS_MCU
select MFD_CORE
select REGMAP
help
If you say yes here you get support for the FAN controlled
by the Microcontroller found on the Khadas VIM boards.
endif endif
...@@ -61,3 +61,4 @@ obj-$(CONFIG_ZX2967_THERMAL) += zx2967_thermal.o ...@@ -61,3 +61,4 @@ obj-$(CONFIG_ZX2967_THERMAL) += zx2967_thermal.o
obj-$(CONFIG_UNIPHIER_THERMAL) += uniphier_thermal.o obj-$(CONFIG_UNIPHIER_THERMAL) += uniphier_thermal.o
obj-$(CONFIG_AMLOGIC_THERMAL) += amlogic_thermal.o obj-$(CONFIG_AMLOGIC_THERMAL) += amlogic_thermal.o
obj-$(CONFIG_SPRD_THERMAL) += sprd_thermal.o obj-$(CONFIG_SPRD_THERMAL) += sprd_thermal.o
obj-$(CONFIG_KHADAS_MCU_FAN_THERMAL) += khadas_mcu_fan.o
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Khadas MCU Controlled FAN driver
*
* Copyright (C) 2020 BayLibre SAS
* Author(s): Neil Armstrong <narmstrong@baylibre.com>
*/
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/mfd/khadas-mcu.h>
#include <linux/regmap.h>
#include <linux/sysfs.h>
#include <linux/thermal.h>
#define MAX_LEVEL 3
struct khadas_mcu_fan_ctx {
struct khadas_mcu *mcu;
unsigned int level;
struct thermal_cooling_device *cdev;
};
static int khadas_mcu_fan_set_level(struct khadas_mcu_fan_ctx *ctx,
unsigned int level)
{
int ret;
ret = regmap_write(ctx->mcu->regmap, KHADAS_MCU_CMD_FAN_STATUS_CTRL_REG,
level);
if (ret)
return ret;
ctx->level = level;
return 0;
}
static int khadas_mcu_fan_get_max_state(struct thermal_cooling_device *cdev,
unsigned long *state)
{
*state = MAX_LEVEL;
return 0;
}
static int khadas_mcu_fan_get_cur_state(struct thermal_cooling_device *cdev,
unsigned long *state)
{
struct khadas_mcu_fan_ctx *ctx = cdev->devdata;
*state = ctx->level;
return 0;
}
static int
khadas_mcu_fan_set_cur_state(struct thermal_cooling_device *cdev,
unsigned long state)
{
struct khadas_mcu_fan_ctx *ctx = cdev->devdata;
if (state > MAX_LEVEL)
return -EINVAL;
if (state == ctx->level)
return 0;
return khadas_mcu_fan_set_level(ctx, state);
}
static const struct thermal_cooling_device_ops khadas_mcu_fan_cooling_ops = {
.get_max_state = khadas_mcu_fan_get_max_state,
.get_cur_state = khadas_mcu_fan_get_cur_state,
.set_cur_state = khadas_mcu_fan_set_cur_state,
};
static int khadas_mcu_fan_probe(struct platform_device *pdev)
{
struct khadas_mcu *mcu = dev_get_drvdata(pdev->dev.parent);
struct thermal_cooling_device *cdev;
struct device *dev = &pdev->dev;
struct khadas_mcu_fan_ctx *ctx;
int ret;
ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;
ctx->mcu = mcu;
platform_set_drvdata(pdev, ctx);
cdev = devm_thermal_of_cooling_device_register(dev->parent,
dev->parent->of_node, "khadas-mcu-fan", ctx,
&khadas_mcu_fan_cooling_ops);
if (IS_ERR(cdev)) {
ret = PTR_ERR(cdev);
dev_err(dev, "Failed to register khadas-mcu-fan as cooling device: %d\n",
ret);
return ret;
}
ctx->cdev = cdev;
thermal_cdev_update(cdev);
return 0;
}
static void khadas_mcu_fan_shutdown(struct platform_device *pdev)
{
struct khadas_mcu_fan_ctx *ctx = platform_get_drvdata(pdev);
khadas_mcu_fan_set_level(ctx, 0);
}
#ifdef CONFIG_PM_SLEEP
static int khadas_mcu_fan_suspend(struct device *dev)
{
struct khadas_mcu_fan_ctx *ctx = dev_get_drvdata(dev);
unsigned int level_save = ctx->level;
int ret;
ret = khadas_mcu_fan_set_level(ctx, 0);
if (ret)
return ret;
ctx->level = level_save;
return 0;
}
static int khadas_mcu_fan_resume(struct device *dev)
{
struct khadas_mcu_fan_ctx *ctx = dev_get_drvdata(dev);
return khadas_mcu_fan_set_level(ctx, ctx->level);
}
#endif
static SIMPLE_DEV_PM_OPS(khadas_mcu_fan_pm, khadas_mcu_fan_suspend,
khadas_mcu_fan_resume);
static const struct platform_device_id khadas_mcu_fan_id_table[] = {
{ .name = "khadas-mcu-fan-ctrl", },
{},
};
MODULE_DEVICE_TABLE(platform, khadas_mcu_fan_id_table);
static struct platform_driver khadas_mcu_fan_driver = {
.probe = khadas_mcu_fan_probe,
.shutdown = khadas_mcu_fan_shutdown,
.driver = {
.name = "khadas-mcu-fan-ctrl",
.pm = &khadas_mcu_fan_pm,
},
.id_table = khadas_mcu_fan_id_table,
};
module_platform_driver(khadas_mcu_fan_driver);
MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
MODULE_DESCRIPTION("Khadas MCU FAN driver");
MODULE_LICENSE("GPL");
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
#define MFD_RES_SIZE(arr) (sizeof(arr) / sizeof(struct resource)) #define MFD_RES_SIZE(arr) (sizeof(arr) / sizeof(struct resource))
#define MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, _compat, _match)\ #define MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, _compat, _of_reg, _use_of_reg, _match) \
{ \ { \
.name = (_name), \ .name = (_name), \
.resources = (_res), \ .resources = (_res), \
...@@ -22,24 +22,32 @@ ...@@ -22,24 +22,32 @@
.platform_data = (_pdata), \ .platform_data = (_pdata), \
.pdata_size = (_pdsize), \ .pdata_size = (_pdsize), \
.of_compatible = (_compat), \ .of_compatible = (_compat), \
.of_reg = (_of_reg), \
.use_of_reg = (_use_of_reg), \
.acpi_match = (_match), \ .acpi_match = (_match), \
.id = (_id), \ .id = (_id), \
} }
#define OF_MFD_CELL(_name, _res, _pdata, _pdsize,_id, _compat) \ #define OF_MFD_CELL_REG(_name, _res, _pdata, _pdsize, _id, _compat, _of_reg) \
MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, _compat, NULL) \ MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, _compat, _of_reg, true, NULL)
#define ACPI_MFD_CELL(_name, _res, _pdata, _pdsize, _id, _match) \ #define OF_MFD_CELL(_name, _res, _pdata, _pdsize, _id, _compat) \
MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, NULL, _match) \ MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, _compat, 0, false, NULL)
#define MFD_CELL_BASIC(_name, _res, _pdata, _pdsize, _id) \ #define ACPI_MFD_CELL(_name, _res, _pdata, _pdsize, _id, _match) \
MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, NULL, NULL) \ MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, NULL, 0, false, _match)
#define MFD_CELL_RES(_name, _res) \ #define MFD_CELL_BASIC(_name, _res, _pdata, _pdsize, _id) \
MFD_CELL_ALL(_name, _res, NULL, 0, 0, NULL, NULL) \ MFD_CELL_ALL(_name, _res, _pdata, _pdsize, _id, NULL, 0, false, NULL)
#define MFD_CELL_NAME(_name) \ #define MFD_CELL_RES(_name, _res) \
MFD_CELL_ALL(_name, NULL, NULL, 0, 0, NULL, NULL) \ MFD_CELL_ALL(_name, _res, NULL, 0, 0, NULL, 0, false, NULL)
#define MFD_CELL_NAME(_name) \
MFD_CELL_ALL(_name, NULL, NULL, 0, 0, NULL, 0, false, NULL)
#define MFD_DEP_LEVEL_NORMAL 0
#define MFD_DEP_LEVEL_HIGH 1
struct irq_domain; struct irq_domain;
struct property_entry; struct property_entry;
...@@ -58,6 +66,7 @@ struct mfd_cell_acpi_match { ...@@ -58,6 +66,7 @@ struct mfd_cell_acpi_match {
struct mfd_cell { struct mfd_cell {
const char *name; const char *name;
int id; int id;
int level;
int (*enable)(struct platform_device *dev); int (*enable)(struct platform_device *dev);
int (*disable)(struct platform_device *dev); int (*disable)(struct platform_device *dev);
...@@ -78,6 +87,16 @@ struct mfd_cell { ...@@ -78,6 +87,16 @@ struct mfd_cell {
*/ */
const char *of_compatible; const char *of_compatible;
/*
* Address as defined in Device Tree. Used to compement 'of_compatible'
* (above) when matching OF nodes with devices that have identical
* compatible strings
*/
const u64 of_reg;
/* Set to 'true' to use 'of_reg' (above) - allows for of_reg=0 */
bool use_of_reg;
/* Matches ACPI */ /* Matches ACPI */
const struct mfd_cell_acpi_match *acpi_match; const struct mfd_cell_acpi_match *acpi_match;
...@@ -135,6 +154,7 @@ static inline int mfd_add_hotplug_devices(struct device *parent, ...@@ -135,6 +154,7 @@ static inline int mfd_add_hotplug_devices(struct device *parent,
} }
extern void mfd_remove_devices(struct device *parent); extern void mfd_remove_devices(struct device *parent);
extern void mfd_remove_devices_late(struct device *parent);
extern int devm_mfd_add_devices(struct device *dev, int id, extern int devm_mfd_add_devices(struct device *dev, int id,
const struct mfd_cell *cells, int n_devs, const struct mfd_cell *cells, int n_devs,
......
...@@ -35,7 +35,7 @@ struct da9055_pdata { ...@@ -35,7 +35,7 @@ struct da9055_pdata {
int *gpio_rsel; int *gpio_rsel;
/* /*
* Regulator mode control bits value (GPI offset) that * Regulator mode control bits value (GPI offset) that
* that controls the regulator state, 0 if not available. * controls the regulator state, 0 if not available.
*/ */
enum gpio_select *reg_ren; enum gpio_select *reg_ren;
/* /*
......
...@@ -35,6 +35,7 @@ enum da9063_variant_codes { ...@@ -35,6 +35,7 @@ enum da9063_variant_codes {
PMIC_DA9063_AD = 0x3, PMIC_DA9063_AD = 0x3,
PMIC_DA9063_BB = 0x5, PMIC_DA9063_BB = 0x5,
PMIC_DA9063_CA = 0x6, PMIC_DA9063_CA = 0x6,
PMIC_DA9063_DA = 0x7,
}; };
/* Interrupts */ /* Interrupts */
......
...@@ -292,8 +292,10 @@ ...@@ -292,8 +292,10 @@
#define DA9063_BB_REG_GP_ID_19 0x134 #define DA9063_BB_REG_GP_ID_19 0x134
/* Chip ID and variant */ /* Chip ID and variant */
#define DA9063_REG_CHIP_ID 0x181 #define DA9063_REG_DEVICE_ID 0x181
#define DA9063_REG_CHIP_VARIANT 0x182 #define DA9063_REG_VARIANT_ID 0x182
#define DA9063_REG_CUSTOMER_ID 0x183
#define DA9063_REG_CONFIG_ID 0x184
/* /*
* PMIC registers bits * PMIC registers bits
...@@ -929,9 +931,6 @@ ...@@ -929,9 +931,6 @@
#define DA9063_RTC_CLOCK 0x40 #define DA9063_RTC_CLOCK 0x40
#define DA9063_OUT_32K_EN 0x80 #define DA9063_OUT_32K_EN 0x80
/* DA9063_REG_CHIP_VARIANT */
#define DA9063_CHIP_VARIANT_SHIFT 4
/* DA9063_REG_BUCK_ILIM_A (addr=0x9A) */ /* DA9063_REG_BUCK_ILIM_A (addr=0x9A) */
#define DA9063_BIO_ILIM_MASK 0x0F #define DA9063_BIO_ILIM_MASK 0x0F
#define DA9063_BMEM_ILIM_MASK 0xF0 #define DA9063_BMEM_ILIM_MASK 0xF0
...@@ -1065,4 +1064,10 @@ ...@@ -1065,4 +1064,10 @@
#define DA9063_MON_A10_IDX_LDO9 0x04 #define DA9063_MON_A10_IDX_LDO9 0x04
#define DA9063_MON_A10_IDX_LDO10 0x05 #define DA9063_MON_A10_IDX_LDO10 0x05
/* DA9063_REG_VARIANT_ID (addr=0x182) */
#define DA9063_VARIANT_ID_VRC_SHIFT 0
#define DA9063_VARIANT_ID_VRC_MASK 0x0F
#define DA9063_VARIANT_ID_MRC_SHIFT 4
#define DA9063_VARIANT_ID_MRC_MASK 0xF0
#endif /* _DA9063_REG_H */ #endif /* _DA9063_REG_H */
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* Copyright (c) <2011-2014> HiSilicon Technologies Co., Ltd. * Copyright (c) <2011-2014> HiSilicon Technologies Co., Ltd.
* http://www.hisilicon.com * http://www.hisilicon.com
* Copyright (c) <2013-2014> Linaro Ltd. * Copyright (c) <2013-2014> Linaro Ltd.
* http://www.linaro.org * https://www.linaro.org
* *
* Author: Guodong Xu <guodong.xu@linaro.org> * Author: Guodong Xu <guodong.xu@linaro.org>
*/ */
......
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Khadas System control Microcontroller Register map
*
* Copyright (C) 2020 BayLibre SAS
*
* Author(s): Neil Armstrong <narmstrong@baylibre.com>
*/
#ifndef MFD_KHADAS_MCU_H
#define MFD_KHADAS_MCU_H
#define KHADAS_MCU_PASSWD_VEN_0_REG 0x00 /* RO */
#define KHADAS_MCU_PASSWD_VEN_1_REG 0x01 /* RO */
#define KHADAS_MCU_PASSWD_VEN_2_REG 0x02 /* RO */
#define KHADAS_MCU_PASSWD_VEN_3_REG 0x03 /* RO */
#define KHADAS_MCU_PASSWD_VEN_4_REG 0x04 /* RO */
#define KHADAS_MCU_PASSWD_VEN_5_REG 0x05 /* RO */
#define KHADAS_MCU_MAC_0_REG 0x06 /* RO */
#define KHADAS_MCU_MAC_1_REG 0x07 /* RO */
#define KHADAS_MCU_MAC_2_REG 0x08 /* RO */
#define KHADAS_MCU_MAC_3_REG 0x09 /* RO */
#define KHADAS_MCU_MAC_4_REG 0x0a /* RO */
#define KHADAS_MCU_MAC_5_REG 0x0b /* RO */
#define KHADAS_MCU_USID_0_REG 0x0c /* RO */
#define KHADAS_MCU_USID_1_REG 0x0d /* RO */
#define KHADAS_MCU_USID_2_REG 0x0e /* RO */
#define KHADAS_MCU_USID_3_REG 0x0f /* RO */
#define KHADAS_MCU_USID_4_REG 0x10 /* RO */
#define KHADAS_MCU_USID_5_REG 0x11 /* RO */
#define KHADAS_MCU_VERSION_0_REG 0x12 /* RO */
#define KHADAS_MCU_VERSION_1_REG 0x13 /* RO */
#define KHADAS_MCU_DEVICE_NO_0_REG 0x14 /* RO */
#define KHADAS_MCU_DEVICE_NO_1_REG 0x15 /* RO */
#define KHADAS_MCU_FACTORY_TEST_REG 0x16 /* R */
#define KHADAS_MCU_BOOT_MODE_REG 0x20 /* RW */
#define KHADAS_MCU_BOOT_EN_WOL_REG 0x21 /* RW */
#define KHADAS_MCU_BOOT_EN_RTC_REG 0x22 /* RW */
#define KHADAS_MCU_BOOT_EN_EXP_REG 0x23 /* RW */
#define KHADAS_MCU_BOOT_EN_IR_REG 0x24 /* RW */
#define KHADAS_MCU_BOOT_EN_DCIN_REG 0x25 /* RW */
#define KHADAS_MCU_BOOT_EN_KEY_REG 0x26 /* RW */
#define KHADAS_MCU_KEY_MODE_REG 0x27 /* RW */
#define KHADAS_MCU_LED_MODE_ON_REG 0x28 /* RW */
#define KHADAS_MCU_LED_MODE_OFF_REG 0x29 /* RW */
#define KHADAS_MCU_SHUTDOWN_NORMAL_REG 0x2c /* RW */
#define KHADAS_MCU_MAC_SWITCH_REG 0x2d /* RW */
#define KHADAS_MCU_MCU_SLEEP_MODE_REG 0x2e /* RW */
#define KHADAS_MCU_IR_CODE1_0_REG 0x2f /* RW */
#define KHADAS_MCU_IR_CODE1_1_REG 0x30 /* RW */
#define KHADAS_MCU_IR_CODE1_2_REG 0x31 /* RW */
#define KHADAS_MCU_IR_CODE1_3_REG 0x32 /* RW */
#define KHADAS_MCU_USB_PCIE_SWITCH_REG 0x33 /* RW */
#define KHADAS_MCU_IR_CODE2_0_REG 0x34 /* RW */
#define KHADAS_MCU_IR_CODE2_1_REG 0x35 /* RW */
#define KHADAS_MCU_IR_CODE2_2_REG 0x36 /* RW */
#define KHADAS_MCU_IR_CODE2_3_REG 0x37 /* RW */
#define KHADAS_MCU_PASSWD_USER_0_REG 0x40 /* RW */
#define KHADAS_MCU_PASSWD_USER_1_REG 0x41 /* RW */
#define KHADAS_MCU_PASSWD_USER_2_REG 0x42 /* RW */
#define KHADAS_MCU_PASSWD_USER_3_REG 0x43 /* RW */
#define KHADAS_MCU_PASSWD_USER_4_REG 0x44 /* RW */
#define KHADAS_MCU_PASSWD_USER_5_REG 0x45 /* RW */
#define KHADAS_MCU_USER_DATA_0_REG 0x46 /* RW 56 bytes */
#define KHADAS_MCU_PWR_OFF_CMD_REG 0x80 /* WO */
#define KHADAS_MCU_PASSWD_START_REG 0x81 /* WO */
#define KHADAS_MCU_CHECK_VEN_PASSWD_REG 0x82 /* WO */
#define KHADAS_MCU_CHECK_USER_PASSWD_REG 0x83 /* WO */
#define KHADAS_MCU_SHUTDOWN_NORMAL_STATUS_REG 0x86 /* RO */
#define KHADAS_MCU_WOL_INIT_START_REG 0x87 /* WO */
#define KHADAS_MCU_CMD_FAN_STATUS_CTRL_REG 0x88 /* WO */
enum {
KHADAS_BOARD_VIM1 = 0x1,
KHADAS_BOARD_VIM2,
KHADAS_BOARD_VIM3,
KHADAS_BOARD_EDGE = 0x11,
KHADAS_BOARD_EDGE_V,
};
/**
* struct khadas_mcu - Khadas MCU structure
* @device: device reference used for logs
* @regmap: register map
*/
struct khadas_mcu {
struct device *dev;
struct regmap *regmap;
};
#endif /* MFD_KHADAS_MCU_H */
/* /*
* Functions to access LP873X power management chip. * Functions to access LP873X power management chip.
* *
* Copyright (C) 2016 Texas Instruments Incorporated - http://www.ti.com/ * Copyright (C) 2016 Texas Instruments Incorporated - https://www.ti.com/
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as * modify it under the terms of the GNU General Public License as
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
/* /*
* Functions to access LP87565 power management chip. * Functions to access LP87565 power management chip.
* *
* Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com/ * Copyright (C) 2017 Texas Instruments Incorporated - https://www.ti.com/
*/ */
#ifndef __LINUX_MFD_LP87565_H #ifndef __LINUX_MFD_LP87565_H
......
...@@ -21,7 +21,6 @@ ...@@ -21,7 +21,6 @@
struct gpio_desc; struct gpio_desc;
struct pinctrl_map; struct pinctrl_map;
struct madera_codec_pdata;
/** /**
* struct madera_pdata - Configuration data for Madera devices * struct madera_pdata - Configuration data for Madera devices
......
...@@ -131,7 +131,7 @@ enum max77693_pmic_reg { ...@@ -131,7 +131,7 @@ enum max77693_pmic_reg {
#define FLASH_INT_FLED1_SHORT BIT(3) #define FLASH_INT_FLED1_SHORT BIT(3)
#define FLASH_INT_OVER_CURRENT BIT(4) #define FLASH_INT_OVER_CURRENT BIT(4)
/* Fast charge timer in in hours */ /* Fast charge timer in hours */
#define DEFAULT_FAST_CHARGE_TIMER 4 #define DEFAULT_FAST_CHARGE_TIMER 4
/* microamps */ /* microamps */
#define DEFAULT_TOP_OFF_THRESHOLD_CURRENT 150000 #define DEFAULT_TOP_OFF_THRESHOLD_CURRENT 150000
......
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* SMSC ECE1099
*
* Copyright 2012 Texas Instruments Inc.
*
* Author: Sourav Poddar <sourav.poddar@ti.com>
*/
#ifndef __LINUX_MFD_SMSC_H
#define __LINUX_MFD_SMSC_H
#include <linux/regmap.h>
#define SMSC_ID_ECE1099 1
#define SMSC_NUM_CLIENTS 2
#define SMSC_BASE_ADDR 0x38
#define OMAP_GPIO_SMSC_IRQ 151
#define SMSC_MAXGPIO 32
#define SMSC_BANK(offs) ((offs) >> 3)
#define SMSC_BIT(offs) (1u << ((offs) & 0x7))
struct smsc {
struct device *dev;
struct i2c_client *i2c_clients[SMSC_NUM_CLIENTS];
struct regmap *regmap;
int clk;
/* Stored chip id */
int id;
};
struct smsc_gpio;
struct smsc_keypad;
static inline int smsc_read(struct device *child, unsigned int reg,
unsigned int *dest)
{
struct smsc *smsc = dev_get_drvdata(child->parent);
return regmap_read(smsc->regmap, reg, dest);
}
static inline int smsc_write(struct device *child, unsigned int reg,
unsigned int value)
{
struct smsc *smsc = dev_get_drvdata(child->parent);
return regmap_write(smsc->regmap, reg, value);
}
/* Registers for SMSC */
#define SMSC_RESET 0xF5
#define SMSC_GRP_INT 0xF9
#define SMSC_CLK_CTRL 0xFA
#define SMSC_WKUP_CTRL 0xFB
#define SMSC_DEV_ID 0xFC
#define SMSC_DEV_REV 0xFD
#define SMSC_VEN_ID_L 0xFE
#define SMSC_VEN_ID_H 0xFF
/* CLK VALUE */
#define SMSC_CLK_VALUE 0x13
/* Registers for function GPIO INPUT */
#define SMSC_GPIO_DATA_IN_START 0x00
/* Registers for function GPIO OUPUT */
#define SMSC_GPIO_DATA_OUT_START 0x05
/* Definitions for SMSC GPIO CONFIGURATION REGISTER*/
#define SMSC_GPIO_INPUT_LOW 0x01
#define SMSC_GPIO_INPUT_RISING 0x09
#define SMSC_GPIO_INPUT_FALLING 0x11
#define SMSC_GPIO_INPUT_BOTH_EDGE 0x19
#define SMSC_GPIO_OUTPUT_PP 0x21
#define SMSC_GPIO_OUTPUT_OP 0x31
#define GRP_INT_STAT 0xf9
#define SMSC_GPI_INT 0x0f
#define SMSC_CFG_START 0x0A
/* Registers for SMSC GPIO INTERRUPT STATUS REGISTER*/
#define SMSC_GPIO_INT_STAT_START 0x32
/* Registers for SMSC GPIO INTERRUPT MASK REGISTER*/
#define SMSC_GPIO_INT_MASK_START 0x37
/* Registers for SMSC function KEYPAD*/
#define SMSC_KP_OUT 0x40
#define SMSC_KP_IN 0x41
#define SMSC_KP_INT_STAT 0x42
#define SMSC_KP_INT_MASK 0x43
/* Definitions for keypad */
#define SMSC_KP_KSO 0x70
#define SMSC_KP_KSI 0x51
#define SMSC_KSO_ALL_LOW 0x20
#define SMSC_KP_SET_LOW_PWR 0x0B
#define SMSC_KP_SET_HIGH 0xFF
#define SMSC_KSO_EVAL 0x00
#endif /* __LINUX_MFD_SMSC_H */
...@@ -27,10 +27,15 @@ ...@@ -27,10 +27,15 @@
#define STM32_LPTIM_CMPOK BIT(3) #define STM32_LPTIM_CMPOK BIT(3)
/* STM32_LPTIM_ICR - bit fields */ /* STM32_LPTIM_ICR - bit fields */
#define STM32_LPTIM_ARRMCF BIT(1)
#define STM32_LPTIM_CMPOKCF_ARROKCF GENMASK(4, 3) #define STM32_LPTIM_CMPOKCF_ARROKCF GENMASK(4, 3)
/* STM32_LPTIM_IER - bit flieds */
#define STM32_LPTIM_ARRMIE BIT(1)
/* STM32_LPTIM_CR - bit fields */ /* STM32_LPTIM_CR - bit fields */
#define STM32_LPTIM_CNTSTRT BIT(2) #define STM32_LPTIM_CNTSTRT BIT(2)
#define STM32_LPTIM_SNGSTRT BIT(1)
#define STM32_LPTIM_ENABLE BIT(0) #define STM32_LPTIM_ENABLE BIT(0)
/* STM32_LPTIM_CFGR - bit fields */ /* STM32_LPTIM_CFGR - bit fields */
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
/* /*
* TI Touch Screen / ADC MFD driver * TI Touch Screen / ADC MFD driver
* *
* Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ * Copyright (C) 2012 Texas Instruments Incorporated - https://www.ti.com/
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as * modify it under the terms of the GNU General Public License as
......
/* /*
* Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/ * Copyright (C) 2015 Texas Instruments Incorporated - https://www.ti.com/
* Andrew F. Davis <afd@ti.com> * Andrew F. Davis <afd@ti.com>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* *
* Functions to access TPS65217 power management chip. * Functions to access TPS65217 power management chip.
* *
* Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ * Copyright (C) 2011 Texas Instruments Incorporated - https://www.ti.com/
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as * modify it under the terms of the GNU General Public License as
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* *
* Functions to access TPS65219 power management chip. * Functions to access TPS65219 power management chip.
* *
* Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ * Copyright (C) 2014 Texas Instruments Incorporated - https://www.ti.com/
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2 as * modify it under the terms of the GNU General Public License version 2 as
......
/* /*
* Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/ * Copyright (C) 2015 Texas Instruments Incorporated - https://www.ti.com/
* Andrew F. Davis <afd@ti.com> * Andrew F. Davis <afd@ti.com>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment