- Core Frameworks
- Add new !TOUCHSCREEN_SUN4I dependency for SUN4I_GPADC - List include/dt-bindings/mfd/* to files supported in MAINTAINERS - New Drivers - Intel Apollo Lake SPI NOR - ST STM32 Timers (Advanced, Basic and PWM) - Motorola 6556002 CPCAP (PMIC) - New Device Support - Add support for AXP221 to axp20x - Add support for Intel Gemini Lake to intel-lpss-pci - Add support for MT6323 LED to mt6397-core - Add support for COMe-bBD#, COMe-bSL6, COMe-bKL6, COMe-cAL6 and COMe-cKL6 to kempld-core - New Functionality - Add support for Analog CODAC to sun6i-prcm - Add support for Watchdog to lpc_ich - Fix-ups - Error handling improvements; axp288_charger, axp20x, ab8500-sysctrl - Adapt platform data handling; axp20x - IRQ handling improvements; arizona, axp20x - Remove superfluous code; arizona, axp20x, lpc_ich - Trivial coding style/spelling fixes; axp20x, abx500, mfd.txt - Regmap fix-ups; axp20x - DT changes; mfd.txt, aspeed-lpc, aspeed-gfx, ab8500-core, tps65912, mt6397 - Use new I2C probing mechanism; max77686 - Constification; rk808 - Bug Fixes - Stop data transfer whilst suspended; cros_ec -----BEGIN PGP SIGNATURE----- iQIcBAABCAAGBQJYrYwQAAoJEFGvii+H/HdhVMMP/3Y5/S1y7bCRhsta3PQVHT/2 +nxu833451qTTUKNqR5rTQrjdjVLr6+rfhMmMxIDhHMrn3EvwT0bQDQmncLLYgc2 u5n2j93Y/nfyJvy76W3aTlisBaKfxhFBuLBEkewXNwPaZk97tbgf9IbyNq6eirHo afv5Z54q9RN+OlT5ZfM8mJcOQAdyE6CXzq/GKZI6LjSqPb5vQhasqoD/yb9pMMga jYseI47KlIVLhUnnAjxRdxt16rjtee2JHZmGCGJaeo+nWiTwDOZ5l5eZDHKwD6ng 3CW4xWDPbzeLD22oi6Uzvhx+8Eqt9S/K1AY+kn3W6WLk/CTi5yamMHw0DjBUcS9a hqdqGZrCSveRQrSCt/9N5uzSMkiUHFMGdj5LtX3yB4fDp0R42WJGMxkvidKb7otB wJIT0i5T5M5G3IT3xPkdEtfEAK3xoAus+IF0faFNaD7GqsEs97KD+740nTgulSKz g28Lo6NLpZhl+uQ74fx76Wll+Onj1voWABZW8Z//kjRWkAwKU8OhbXrX8kccGY6m C980wWtj0979jYFstwUuSXspjuvk9L1nfSuLBmtawm9S58TUIS/WLe2A8kU9/XEY e3PLpO4AxvCJvBBa80yVFG15JoaTX5TOg/F3NqKYaHqA2cusOVOEFAeOAdwav2rL SR2Y8s8ceIL4n9ccmr0b =P5Dp -----END PGP SIGNATURE----- Merge tag 'mfd-for-linus-4.11' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd Pull MFD updates from Lee Jones: "Core Frameworks: - Add new !TOUCHSCREEN_SUN4I dependency for SUN4I_GPADC - List include/dt-bindings/mfd/* to files supported in MAINTAINERS New Drivers: - Intel Apollo Lake SPI NOR - ST STM32 Timers (Advanced, Basic and PWM) - Motorola 6556002 CPCAP (PMIC) New Device Support: - Add support for AXP221 to axp20x - Add support for Intel Gemini Lake to intel-lpss-pci - Add support for MT6323 LED to mt6397-core - Add support for COMe-bBD#, COMe-bSL6, COMe-bKL6, COMe-cAL6 and COMe-cKL6 to kempld-core New Functionality: - Add support for Analog CODAC to sun6i-prcm - Add support for Watchdog to lpc_ich Fix-ups: - Error handling improvements; axp288_charger, axp20x, ab8500-sysctrl - Adapt platform data handling; axp20x - IRQ handling improvements; arizona, axp20x - Remove superfluous code; arizona, axp20x, lpc_ich - Trivial coding style/spelling fixes; axp20x, abx500, mfd.txt - Regmap fix-ups; axp20x - DT changes; mfd.txt, aspeed-lpc, aspeed-gfx, ab8500-core, tps65912, mt6397 - Use new I2C probing mechanism; max77686 - Constification; rk808 Bug Fixes: - Stop data transfer whilst suspended; cros_ec" * tag 'mfd-for-linus-4.11' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd: (43 commits) mfd: lpc_ich: Enable watchdog on Intel Apollo Lake PCH mfd: lpc_ich: Remove useless comments in core part mfd: Add support for several boards to Kontron PLD driver mfd: constify regmap_irq_chip structures MAINTAINERS: Add include/dt-bindings/mfd to MFD entry mfd: cpcap: Add minimal support mfd: mt6397: Add MT6323 LED support into MT6397 driver Documentation: devicetree: Add LED subnode binding for MT6323 PMIC mfd: tps65912: Export OF device ID table as module aliases mfd: ab8500-core: Rename clock device and compatible mfd: cros_ec: Send correct suspend/resume event to EC mfd: max77686: Remove I2C device ID table mfd: max77686: Use the struct i2c_driver .probe_new instead of .probe mfd: max77686: Use of_device_get_match_data() helper mfd: max77686: Don't attempt to get i2c_device_id .data mfd: ab8500-sysctrl: Handle probe deferral mfd: intel-lpss: Add Intel Gemini Lake PCI IDs mfd: axp20x: Fix AXP806 access errors on cold boot mfd: cros_ec: Send suspend state notification to EC mfd: cros_ec: Prevent data transfer while device is suspended ...
This commit is contained in:
commit
df9cdc1727
|
@ -0,0 +1,17 @@
|
|||
* Device tree bindings for Aspeed SoC Display Controller (GFX)
|
||||
|
||||
The Aspeed SoC Display Controller primarily does as its name suggests, but also
|
||||
participates in pinmux requests on the g5 SoCs. It is therefore considered a
|
||||
syscon device.
|
||||
|
||||
Required properties:
|
||||
- compatible: "aspeed,ast2500-gfx", "syscon"
|
||||
- reg: contains offset/length value of the GFX memory
|
||||
region.
|
||||
|
||||
Example:
|
||||
|
||||
gfx: display@1e6e6000 {
|
||||
compatible = "aspeed,ast2500-gfx", "syscon";
|
||||
reg = <0x1e6e6000 0x1000>;
|
||||
};
|
|
@ -0,0 +1,137 @@
|
|||
======================================================================
|
||||
Device tree bindings for the Aspeed Low Pin Count (LPC) Bus Controller
|
||||
======================================================================
|
||||
|
||||
The LPC bus is a means to bridge a host CPU to a number of low-bandwidth
|
||||
peripheral devices, replacing the use of the ISA bus in the age of PCI[0]. The
|
||||
primary use case of the Aspeed LPC controller is as a slave on the bus
|
||||
(typically in a Baseboard Management Controller SoC), but under certain
|
||||
conditions it can also take the role of bus master.
|
||||
|
||||
The LPC controller is represented as a multi-function device to account for the
|
||||
mix of functionality it provides. The principle split is between the register
|
||||
layout at the start of the I/O space which is, to quote the Aspeed datasheet,
|
||||
"basically compatible with the [LPC registers from the] popular BMC controller
|
||||
H8S/2168[1]", and everything else, where everything else is an eclectic
|
||||
collection of functions with a esoteric register layout. "Everything else",
|
||||
here labeled the "host" portion of the controller, includes, but is not limited
|
||||
to:
|
||||
|
||||
* An IPMI Block Transfer[2] Controller
|
||||
|
||||
* An LPC Host Controller: Manages LPC functions such as host vs slave mode, the
|
||||
physical properties of some LPC pins, configuration of serial IRQs, and
|
||||
APB-to-LPC bridging amonst other functions.
|
||||
|
||||
* An LPC Host Interface Controller: Manages functions exposed to the host such
|
||||
as LPC firmware hub cycles, configuration of the LPC-to-AHB mapping, UART
|
||||
management and bus snoop configuration.
|
||||
|
||||
* A set of SuperIO[3] scratch registers: Enables implementation of e.g. custom
|
||||
hardware management protocols for handover between the host and baseboard
|
||||
management controller.
|
||||
|
||||
Additionally the state of the LPC controller influences the pinmux
|
||||
configuration, therefore the host portion of the controller is exposed as a
|
||||
syscon as a means to arbitrate access.
|
||||
|
||||
[0] http://www.intel.com/design/chipsets/industry/25128901.pdf
|
||||
[1] https://www.renesas.com/en-sg/doc/products/mpumcu/001/rej09b0078_h8s2168.pdf?key=7c88837454702128622bee53acbda8f4
|
||||
[2] http://www.intel.com/content/dam/www/public/us/en/documents/product-briefs/ipmi-second-gen-interface-spec-v2-rev1-1.pdf
|
||||
[3] https://en.wikipedia.org/wiki/Super_I/O
|
||||
|
||||
Required properties
|
||||
===================
|
||||
|
||||
- compatible: One of:
|
||||
"aspeed,ast2400-lpc", "simple-mfd"
|
||||
"aspeed,ast2500-lpc", "simple-mfd"
|
||||
|
||||
- reg: contains the physical address and length values of the Aspeed
|
||||
LPC memory region.
|
||||
|
||||
- #address-cells: <1>
|
||||
- #size-cells: <1>
|
||||
- ranges: Maps 0 to the physical address and length of the LPC memory
|
||||
region
|
||||
|
||||
Required LPC Child nodes
|
||||
========================
|
||||
|
||||
BMC Node
|
||||
--------
|
||||
|
||||
- compatible: One of:
|
||||
"aspeed,ast2400-lpc-bmc"
|
||||
"aspeed,ast2500-lpc-bmc"
|
||||
|
||||
- reg: contains the physical address and length values of the
|
||||
H8S/2168-compatible LPC controller memory region
|
||||
|
||||
Host Node
|
||||
---------
|
||||
|
||||
- compatible: One of:
|
||||
"aspeed,ast2400-lpc-host", "simple-mfd", "syscon"
|
||||
"aspeed,ast2500-lpc-host", "simple-mfd", "syscon"
|
||||
|
||||
- reg: contains the address and length values of the host-related
|
||||
register space for the Aspeed LPC controller
|
||||
|
||||
- #address-cells: <1>
|
||||
- #size-cells: <1>
|
||||
- ranges: Maps 0 to the address and length of the host-related LPC memory
|
||||
region
|
||||
|
||||
Example:
|
||||
|
||||
lpc: lpc@1e789000 {
|
||||
compatible = "aspeed,ast2500-lpc", "simple-mfd";
|
||||
reg = <0x1e789000 0x1000>;
|
||||
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
ranges = <0x0 0x1e789000 0x1000>;
|
||||
|
||||
lpc_bmc: lpc-bmc@0 {
|
||||
compatible = "aspeed,ast2500-lpc-bmc";
|
||||
reg = <0x0 0x80>;
|
||||
};
|
||||
|
||||
lpc_host: lpc-host@80 {
|
||||
compatible = "aspeed,ast2500-lpc-host", "simple-mfd", "syscon";
|
||||
reg = <0x80 0x1e0>;
|
||||
reg-io-width = <4>;
|
||||
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
ranges = <0x0 0x80 0x1e0>;
|
||||
};
|
||||
};
|
||||
|
||||
Host Node Children
|
||||
==================
|
||||
|
||||
LPC Host Controller
|
||||
-------------------
|
||||
|
||||
The Aspeed LPC Host Controller configures the Low Pin Count (LPC) bus behaviour
|
||||
between the host and the baseboard management controller. The registers exist
|
||||
in the "host" portion of the Aspeed LPC controller, which must be the parent of
|
||||
the LPC host controller node.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: One of:
|
||||
"aspeed,ast2400-lhc";
|
||||
"aspeed,ast2500-lhc";
|
||||
|
||||
- reg: contains offset/length values of the LHC memory regions. In the
|
||||
AST2400 and AST2500 there are two regions.
|
||||
|
||||
Example:
|
||||
|
||||
lhc: lhc@20 {
|
||||
compatible = "aspeed,ast2500-lhc";
|
||||
reg = <0x20 0x24 0x48 0x8>;
|
||||
};
|
|
@ -19,12 +19,22 @@ Optional properties:
|
|||
|
||||
- compatible : "simple-mfd" - this signifies that the operating system should
|
||||
consider all subnodes of the MFD device as separate devices akin to how
|
||||
"simple-bus" inidicates when to see subnodes as children for a simple
|
||||
"simple-bus" indicates when to see subnodes as children for a simple
|
||||
memory-mapped bus. For more complex devices, when the nexus driver has to
|
||||
probe registers to figure out what child devices exist etc, this should not
|
||||
be used. In the latter case the child devices will be determined by the
|
||||
operating system.
|
||||
|
||||
- ranges: Describes the address mapping relationship to the parent. Should set
|
||||
the child's base address to 0, the physical address within parent's address
|
||||
space, and the length of the address map.
|
||||
|
||||
- #address-cells: Specifies the number of cells used to represent physical base
|
||||
addresses. Must be present if ranges is used.
|
||||
|
||||
- #size-cells: Specifies the number of cells used to represent the size of an
|
||||
address. Must be present if ranges is used.
|
||||
|
||||
Example:
|
||||
|
||||
foo@1000 {
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
Motorola CPCAP PMIC device tree binding
|
||||
|
||||
Required properties:
|
||||
- compatible : One or both of "motorola,cpcap" or "ste,6556002"
|
||||
- reg : SPI chip select
|
||||
- interrupt-parent : The parent interrupt controller
|
||||
- interrupts : The interrupt line the device is connected to
|
||||
- interrupt-controller : Marks the device node as an interrupt controller
|
||||
- #interrupt-cells : The number of cells to describe an IRQ, should be 2
|
||||
- #address-cells : Child device offset number of cells, should be 1
|
||||
- #size-cells : Child device size number of cells, should be 0
|
||||
- spi-max-frequency : Typically set to 3000000
|
||||
- spi-cs-high : SPI chip select direction
|
||||
|
||||
Example:
|
||||
|
||||
&mcspi1 {
|
||||
cpcap: pmic@0 {
|
||||
compatible = "motorola,cpcap", "ste,6556002";
|
||||
reg = <0>; /* cs0 */
|
||||
interrupt-parent = <&gpio1>;
|
||||
interrupts = <7 IRQ_TYPE_EDGE_RISING>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
spi-max-frequency = <3000000>;
|
||||
spi-cs-high;
|
||||
};
|
||||
};
|
||||
|
|
@ -34,6 +34,10 @@ Optional subnodes:
|
|||
- clk
|
||||
Required properties:
|
||||
- compatible: "mediatek,mt6397-clk"
|
||||
- led
|
||||
Required properties:
|
||||
- compatible: "mediatek,mt6323-led"
|
||||
see Documentation/devicetree/bindings/leds/leds-mt6323.txt
|
||||
|
||||
Example:
|
||||
pwrap: pwrap@1000f000 {
|
||||
|
|
|
@ -8476,6 +8476,7 @@ S: Supported
|
|||
F: Documentation/devicetree/bindings/mfd/
|
||||
F: drivers/mfd/
|
||||
F: include/linux/mfd/
|
||||
F: include/dt-bindings/mfd/
|
||||
|
||||
MULTIMEDIA CARD (MMC), SECURE DIGITAL (SD) AND SDIO SUBSYSTEM
|
||||
M: Ulf Hansson <ulf.hansson@linaro.org>
|
||||
|
|
|
@ -34,6 +34,8 @@
|
|||
#include <linux/mfd/cros_ec.h>
|
||||
#include <linux/mfd/cros_ec_commands.h>
|
||||
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
/*
|
||||
* @rows: Number of rows in the keypad
|
||||
* @cols: Number of columns in the keypad
|
||||
|
@ -43,8 +45,9 @@
|
|||
* @valid_keys: bitmap of existing keys for each matrix column
|
||||
* @old_kb_state: bitmap of keys pressed last scan
|
||||
* @dev: Device pointer
|
||||
* @idev: Input device
|
||||
* @ec: Top level ChromeOS device to use to talk to EC
|
||||
* @idev: The input device for the matrix keys.
|
||||
* @bs_idev: The input device for non-matrix buttons and switches (or NULL).
|
||||
* @notifier: interrupt event notifier for transport devices
|
||||
*/
|
||||
struct cros_ec_keyb {
|
||||
|
@ -57,12 +60,64 @@ struct cros_ec_keyb {
|
|||
uint8_t *old_kb_state;
|
||||
|
||||
struct device *dev;
|
||||
struct input_dev *idev;
|
||||
struct cros_ec_device *ec;
|
||||
|
||||
struct input_dev *idev;
|
||||
struct input_dev *bs_idev;
|
||||
struct notifier_block notifier;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* cros_ec_bs_map - Struct mapping Linux keycodes to EC button/switch bitmap
|
||||
* #defines
|
||||
*
|
||||
* @ev_type: The type of the input event to generate (e.g., EV_KEY).
|
||||
* @code: A linux keycode
|
||||
* @bit: A #define like EC_MKBP_POWER_BUTTON or EC_MKBP_LID_OPEN
|
||||
* @inverted: If the #define and EV_SW have opposite meanings, this is true.
|
||||
* Only applicable to switches.
|
||||
*/
|
||||
struct cros_ec_bs_map {
|
||||
unsigned int ev_type;
|
||||
unsigned int code;
|
||||
u8 bit;
|
||||
bool inverted;
|
||||
};
|
||||
|
||||
/* cros_ec_keyb_bs - Map EC button/switch #defines into kernel ones */
|
||||
static const struct cros_ec_bs_map cros_ec_keyb_bs[] = {
|
||||
/* Buttons */
|
||||
{
|
||||
.ev_type = EV_KEY,
|
||||
.code = KEY_POWER,
|
||||
.bit = EC_MKBP_POWER_BUTTON,
|
||||
},
|
||||
{
|
||||
.ev_type = EV_KEY,
|
||||
.code = KEY_VOLUMEUP,
|
||||
.bit = EC_MKBP_VOL_UP,
|
||||
},
|
||||
{
|
||||
.ev_type = EV_KEY,
|
||||
.code = KEY_VOLUMEDOWN,
|
||||
.bit = EC_MKBP_VOL_DOWN,
|
||||
},
|
||||
|
||||
/* Switches */
|
||||
{
|
||||
.ev_type = EV_SW,
|
||||
.code = SW_LID,
|
||||
.bit = EC_MKBP_LID_OPEN,
|
||||
.inverted = true,
|
||||
},
|
||||
{
|
||||
.ev_type = EV_SW,
|
||||
.code = SW_TABLET_MODE,
|
||||
.bit = EC_MKBP_TABLET_MODE,
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
* Returns true when there is at least one combination of pressed keys that
|
||||
* results in ghosting.
|
||||
|
@ -149,20 +204,33 @@ static void cros_ec_keyb_process(struct cros_ec_keyb *ckdev,
|
|||
input_sync(ckdev->idev);
|
||||
}
|
||||
|
||||
static int cros_ec_keyb_open(struct input_dev *dev)
|
||||
{
|
||||
struct cros_ec_keyb *ckdev = input_get_drvdata(dev);
|
||||
/**
|
||||
* cros_ec_keyb_report_bs - Report non-matrixed buttons or switches
|
||||
*
|
||||
* This takes a bitmap of buttons or switches from the EC and reports events,
|
||||
* syncing at the end.
|
||||
*
|
||||
* @ckdev: The keyboard device.
|
||||
* @ev_type: The input event type (e.g., EV_KEY).
|
||||
* @mask: A bitmap of buttons from the EC.
|
||||
*/
|
||||
static void cros_ec_keyb_report_bs(struct cros_ec_keyb *ckdev,
|
||||
unsigned int ev_type, u32 mask)
|
||||
|
||||
return blocking_notifier_chain_register(&ckdev->ec->event_notifier,
|
||||
&ckdev->notifier);
|
||||
{
|
||||
struct input_dev *idev = ckdev->bs_idev;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(cros_ec_keyb_bs); i++) {
|
||||
const struct cros_ec_bs_map *map = &cros_ec_keyb_bs[i];
|
||||
|
||||
if (map->ev_type != ev_type)
|
||||
continue;
|
||||
|
||||
input_event(idev, ev_type, map->code,
|
||||
!!(mask & BIT(map->bit)) ^ map->inverted);
|
||||
}
|
||||
|
||||
static void cros_ec_keyb_close(struct input_dev *dev)
|
||||
{
|
||||
struct cros_ec_keyb *ckdev = input_get_drvdata(dev);
|
||||
|
||||
blocking_notifier_chain_unregister(&ckdev->ec->event_notifier,
|
||||
&ckdev->notifier);
|
||||
input_sync(idev);
|
||||
}
|
||||
|
||||
static int cros_ec_keyb_work(struct notifier_block *nb,
|
||||
|
@ -170,22 +238,54 @@ static int cros_ec_keyb_work(struct notifier_block *nb,
|
|||
{
|
||||
struct cros_ec_keyb *ckdev = container_of(nb, struct cros_ec_keyb,
|
||||
notifier);
|
||||
u32 val;
|
||||
unsigned int ev_type;
|
||||
|
||||
if (ckdev->ec->event_data.event_type != EC_MKBP_EVENT_KEY_MATRIX)
|
||||
return NOTIFY_DONE;
|
||||
switch (ckdev->ec->event_data.event_type) {
|
||||
case EC_MKBP_EVENT_KEY_MATRIX:
|
||||
/*
|
||||
* If EC is not the wake source, discard key state changes during
|
||||
* suspend.
|
||||
* If EC is not the wake source, discard key state changes
|
||||
* during suspend.
|
||||
*/
|
||||
if (queued_during_suspend)
|
||||
return NOTIFY_OK;
|
||||
|
||||
if (ckdev->ec->event_size != ckdev->cols) {
|
||||
dev_err(ckdev->dev,
|
||||
"Discarded incomplete key matrix event.\n");
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
cros_ec_keyb_process(ckdev, ckdev->ec->event_data.data.key_matrix,
|
||||
cros_ec_keyb_process(ckdev,
|
||||
ckdev->ec->event_data.data.key_matrix,
|
||||
ckdev->ec->event_size);
|
||||
break;
|
||||
|
||||
case EC_MKBP_EVENT_BUTTON:
|
||||
case EC_MKBP_EVENT_SWITCH:
|
||||
/*
|
||||
* If EC is not the wake source, discard key state
|
||||
* changes during suspend. Switches will be re-checked in
|
||||
* cros_ec_keyb_resume() to be sure nothing is lost.
|
||||
*/
|
||||
if (queued_during_suspend)
|
||||
return NOTIFY_OK;
|
||||
|
||||
if (ckdev->ec->event_data.event_type == EC_MKBP_EVENT_BUTTON) {
|
||||
val = get_unaligned_le32(
|
||||
&ckdev->ec->event_data.data.buttons);
|
||||
ev_type = EV_KEY;
|
||||
} else {
|
||||
val = get_unaligned_le32(
|
||||
&ckdev->ec->event_data.data.switches);
|
||||
ev_type = EV_SW;
|
||||
}
|
||||
cros_ec_keyb_report_bs(ckdev, ev_type, val);
|
||||
break;
|
||||
|
||||
default:
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
|
@ -213,22 +313,228 @@ static void cros_ec_keyb_compute_valid_keys(struct cros_ec_keyb *ckdev)
|
|||
}
|
||||
}
|
||||
|
||||
static int cros_ec_keyb_probe(struct platform_device *pdev)
|
||||
/**
|
||||
* cros_ec_keyb_info - Wrap the EC command EC_CMD_MKBP_INFO
|
||||
*
|
||||
* This wraps the EC_CMD_MKBP_INFO, abstracting out all of the marshalling and
|
||||
* unmarshalling and different version nonsense into something simple.
|
||||
*
|
||||
* @ec_dev: The EC device
|
||||
* @info_type: Either EC_MKBP_INFO_SUPPORTED or EC_MKBP_INFO_CURRENT.
|
||||
* @event_type: Either EC_MKBP_EVENT_BUTTON or EC_MKBP_EVENT_SWITCH. Actually
|
||||
* in some cases this could be EC_MKBP_EVENT_KEY_MATRIX or
|
||||
* EC_MKBP_EVENT_HOST_EVENT too but we don't use in this driver.
|
||||
* @result: Where we'll store the result; a union
|
||||
* @result_size: The size of the result. Expected to be the size of one of
|
||||
* the elements in the union.
|
||||
*
|
||||
* Returns 0 if no error or -error upon error.
|
||||
*/
|
||||
static int cros_ec_keyb_info(struct cros_ec_device *ec_dev,
|
||||
enum ec_mkbp_info_type info_type,
|
||||
enum ec_mkbp_event event_type,
|
||||
union ec_response_get_next_data *result,
|
||||
size_t result_size)
|
||||
{
|
||||
struct cros_ec_device *ec = dev_get_drvdata(pdev->dev.parent);
|
||||
struct device *dev = &pdev->dev;
|
||||
struct cros_ec_keyb *ckdev;
|
||||
struct ec_params_mkbp_info *params;
|
||||
struct cros_ec_command *msg;
|
||||
int ret;
|
||||
|
||||
msg = kzalloc(sizeof(*msg) + max_t(size_t, result_size,
|
||||
sizeof(*params)), GFP_KERNEL);
|
||||
if (!msg)
|
||||
return -ENOMEM;
|
||||
|
||||
msg->command = EC_CMD_MKBP_INFO;
|
||||
msg->version = 1;
|
||||
msg->outsize = sizeof(*params);
|
||||
msg->insize = result_size;
|
||||
params = (struct ec_params_mkbp_info *)msg->data;
|
||||
params->info_type = info_type;
|
||||
params->event_type = event_type;
|
||||
|
||||
ret = cros_ec_cmd_xfer(ec_dev, msg);
|
||||
if (ret < 0) {
|
||||
dev_warn(ec_dev->dev, "Transfer error %d/%d: %d\n",
|
||||
(int)info_type, (int)event_type, ret);
|
||||
} else if (msg->result == EC_RES_INVALID_VERSION) {
|
||||
/* With older ECs we just return 0 for everything */
|
||||
memset(result, 0, result_size);
|
||||
ret = 0;
|
||||
} else if (msg->result != EC_RES_SUCCESS) {
|
||||
dev_warn(ec_dev->dev, "Error getting info %d/%d: %d\n",
|
||||
(int)info_type, (int)event_type, msg->result);
|
||||
ret = -EPROTO;
|
||||
} else if (ret != result_size) {
|
||||
dev_warn(ec_dev->dev, "Wrong size %d/%d: %d != %zu\n",
|
||||
(int)info_type, (int)event_type,
|
||||
ret, result_size);
|
||||
ret = -EPROTO;
|
||||
} else {
|
||||
memcpy(result, msg->data, result_size);
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
kfree(msg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* cros_ec_keyb_query_switches - Query the state of switches and report
|
||||
*
|
||||
* This will ask the EC about the current state of switches and report to the
|
||||
* kernel. Note that we don't query for buttons because they are more
|
||||
* transitory and we'll get an update on the next release / press.
|
||||
*
|
||||
* @ckdev: The keyboard device
|
||||
*
|
||||
* Returns 0 if no error or -error upon error.
|
||||
*/
|
||||
static int cros_ec_keyb_query_switches(struct cros_ec_keyb *ckdev)
|
||||
{
|
||||
struct cros_ec_device *ec_dev = ckdev->ec;
|
||||
union ec_response_get_next_data event_data = {};
|
||||
int ret;
|
||||
|
||||
ret = cros_ec_keyb_info(ec_dev, EC_MKBP_INFO_CURRENT,
|
||||
EC_MKBP_EVENT_SWITCH, &event_data,
|
||||
sizeof(event_data.switches));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
cros_ec_keyb_report_bs(ckdev, EV_SW,
|
||||
get_unaligned_le32(&event_data.switches));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* cros_ec_keyb_resume - Resume the keyboard
|
||||
*
|
||||
* We use the resume notification as a chance to query the EC for switches.
|
||||
*
|
||||
* @dev: The keyboard device
|
||||
*
|
||||
* Returns 0 if no error or -error upon error.
|
||||
*/
|
||||
static __maybe_unused int cros_ec_keyb_resume(struct device *dev)
|
||||
{
|
||||
struct cros_ec_keyb *ckdev = dev_get_drvdata(dev);
|
||||
|
||||
if (ckdev->bs_idev)
|
||||
return cros_ec_keyb_query_switches(ckdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* cros_ec_keyb_register_bs - Register non-matrix buttons/switches
|
||||
*
|
||||
* Handles all the bits of the keyboard driver related to non-matrix buttons
|
||||
* and switches, including asking the EC about which are present and telling
|
||||
* the kernel to expect them.
|
||||
*
|
||||
* If this device has no support for buttons and switches we'll return no error
|
||||
* but the ckdev->bs_idev will remain NULL when this function exits.
|
||||
*
|
||||
* @ckdev: The keyboard device
|
||||
*
|
||||
* Returns 0 if no error or -error upon error.
|
||||
*/
|
||||
static int cros_ec_keyb_register_bs(struct cros_ec_keyb *ckdev)
|
||||
{
|
||||
struct cros_ec_device *ec_dev = ckdev->ec;
|
||||
struct device *dev = ckdev->dev;
|
||||
struct input_dev *idev;
|
||||
struct device_node *np;
|
||||
union ec_response_get_next_data event_data = {};
|
||||
const char *phys;
|
||||
u32 buttons;
|
||||
u32 switches;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
ret = cros_ec_keyb_info(ec_dev, EC_MKBP_INFO_SUPPORTED,
|
||||
EC_MKBP_EVENT_BUTTON, &event_data,
|
||||
sizeof(event_data.buttons));
|
||||
if (ret)
|
||||
return ret;
|
||||
buttons = get_unaligned_le32(&event_data.buttons);
|
||||
|
||||
ret = cros_ec_keyb_info(ec_dev, EC_MKBP_INFO_SUPPORTED,
|
||||
EC_MKBP_EVENT_SWITCH, &event_data,
|
||||
sizeof(event_data.switches));
|
||||
if (ret)
|
||||
return ret;
|
||||
switches = get_unaligned_le32(&event_data.switches);
|
||||
|
||||
if (!buttons && !switches)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* We call the non-matrix buttons/switches 'input1', if present.
|
||||
* Allocate phys before input dev, to ensure correct tear-down
|
||||
* ordering.
|
||||
*/
|
||||
phys = devm_kasprintf(dev, GFP_KERNEL, "%s/input1", ec_dev->phys_name);
|
||||
if (!phys)
|
||||
return -ENOMEM;
|
||||
|
||||
idev = devm_input_allocate_device(dev);
|
||||
if (!idev)
|
||||
return -ENOMEM;
|
||||
|
||||
idev->name = "cros_ec_buttons";
|
||||
idev->phys = phys;
|
||||
__set_bit(EV_REP, idev->evbit);
|
||||
|
||||
idev->id.bustype = BUS_VIRTUAL;
|
||||
idev->id.version = 1;
|
||||
idev->id.product = 0;
|
||||
idev->dev.parent = dev;
|
||||
|
||||
input_set_drvdata(idev, ckdev);
|
||||
ckdev->bs_idev = idev;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(cros_ec_keyb_bs); i++) {
|
||||
const struct cros_ec_bs_map *map = &cros_ec_keyb_bs[i];
|
||||
|
||||
if (buttons & BIT(map->bit))
|
||||
input_set_capability(idev, map->ev_type, map->code);
|
||||
}
|
||||
|
||||
ret = cros_ec_keyb_query_switches(ckdev);
|
||||
if (ret) {
|
||||
dev_err(dev, "cannot query switches\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = input_register_device(ckdev->bs_idev);
|
||||
if (ret) {
|
||||
dev_err(dev, "cannot register input device\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* cros_ec_keyb_register_bs - Register matrix keys
|
||||
*
|
||||
* Handles all the bits of the keyboard driver related to matrix keys.
|
||||
*
|
||||
* @ckdev: The keyboard device
|
||||
*
|
||||
* Returns 0 if no error or -error upon error.
|
||||
*/
|
||||
static int cros_ec_keyb_register_matrix(struct cros_ec_keyb *ckdev)
|
||||
{
|
||||
struct cros_ec_device *ec_dev = ckdev->ec;
|
||||
struct device *dev = ckdev->dev;
|
||||
struct input_dev *idev;
|
||||
const char *phys;
|
||||
int err;
|
||||
|
||||
np = pdev->dev.of_node;
|
||||
if (!np)
|
||||
return -ENODEV;
|
||||
|
||||
ckdev = devm_kzalloc(dev, sizeof(*ckdev), GFP_KERNEL);
|
||||
if (!ckdev)
|
||||
return -ENOMEM;
|
||||
err = matrix_keypad_parse_of_params(dev, &ckdev->rows, &ckdev->cols);
|
||||
if (err)
|
||||
return err;
|
||||
|
@ -241,27 +547,28 @@ static int cros_ec_keyb_probe(struct platform_device *pdev)
|
|||
if (!ckdev->old_kb_state)
|
||||
return -ENOMEM;
|
||||
|
||||
/*
|
||||
* We call the keyboard matrix 'input0'. Allocate phys before input
|
||||
* dev, to ensure correct tear-down ordering.
|
||||
*/
|
||||
phys = devm_kasprintf(dev, GFP_KERNEL, "%s/input0", ec_dev->phys_name);
|
||||
if (!phys)
|
||||
return -ENOMEM;
|
||||
|
||||
idev = devm_input_allocate_device(dev);
|
||||
if (!idev)
|
||||
return -ENOMEM;
|
||||
|
||||
ckdev->ec = ec;
|
||||
ckdev->notifier.notifier_call = cros_ec_keyb_work;
|
||||
ckdev->dev = dev;
|
||||
dev_set_drvdata(dev, ckdev);
|
||||
|
||||
idev->name = CROS_EC_DEV_NAME;
|
||||
idev->phys = ec->phys_name;
|
||||
idev->phys = phys;
|
||||
__set_bit(EV_REP, idev->evbit);
|
||||
|
||||
idev->id.bustype = BUS_VIRTUAL;
|
||||
idev->id.version = 1;
|
||||
idev->id.product = 0;
|
||||
idev->dev.parent = dev;
|
||||
idev->open = cros_ec_keyb_open;
|
||||
idev->close = cros_ec_keyb_close;
|
||||
|
||||
ckdev->ghost_filter = of_property_read_bool(np,
|
||||
ckdev->ghost_filter = of_property_read_bool(dev->of_node,
|
||||
"google,needs-ghost-filter");
|
||||
|
||||
err = matrix_keypad_build_keymap(NULL, NULL, ckdev->rows, ckdev->cols,
|
||||
|
@ -287,6 +594,57 @@ static int cros_ec_keyb_probe(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int cros_ec_keyb_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct cros_ec_device *ec = dev_get_drvdata(pdev->dev.parent);
|
||||
struct device *dev = &pdev->dev;
|
||||
struct cros_ec_keyb *ckdev;
|
||||
int err;
|
||||
|
||||
if (!dev->of_node)
|
||||
return -ENODEV;
|
||||
|
||||
ckdev = devm_kzalloc(dev, sizeof(*ckdev), GFP_KERNEL);
|
||||
if (!ckdev)
|
||||
return -ENOMEM;
|
||||
|
||||
ckdev->ec = ec;
|
||||
ckdev->dev = dev;
|
||||
dev_set_drvdata(dev, ckdev);
|
||||
|
||||
err = cros_ec_keyb_register_matrix(ckdev);
|
||||
if (err) {
|
||||
dev_err(dev, "cannot register matrix inputs: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = cros_ec_keyb_register_bs(ckdev);
|
||||
if (err) {
|
||||
dev_err(dev, "cannot register non-matrix inputs: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
ckdev->notifier.notifier_call = cros_ec_keyb_work;
|
||||
err = blocking_notifier_chain_register(&ckdev->ec->event_notifier,
|
||||
&ckdev->notifier);
|
||||
if (err) {
|
||||
dev_err(dev, "cannot register notifier: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cros_ec_keyb_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct cros_ec_keyb *ckdev = dev_get_drvdata(&pdev->dev);
|
||||
|
||||
blocking_notifier_chain_unregister(&ckdev->ec->event_notifier,
|
||||
&ckdev->notifier);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id cros_ec_keyb_of_match[] = {
|
||||
{ .compatible = "google,cros-ec-keyb" },
|
||||
|
@ -295,11 +653,15 @@ static const struct of_device_id cros_ec_keyb_of_match[] = {
|
|||
MODULE_DEVICE_TABLE(of, cros_ec_keyb_of_match);
|
||||
#endif
|
||||
|
||||
static const SIMPLE_DEV_PM_OPS(cros_ec_keyb_pm_ops, NULL, cros_ec_keyb_resume);
|
||||
|
||||
static struct platform_driver cros_ec_keyb_driver = {
|
||||
.probe = cros_ec_keyb_probe,
|
||||
.remove = cros_ec_keyb_remove,
|
||||
.driver = {
|
||||
.name = "cros-ec-keyb",
|
||||
.of_match_table = of_match_ptr(cros_ec_keyb_of_match),
|
||||
.pm = &cros_ec_keyb_pm_ops,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -46,6 +46,7 @@ config MFD_SUN4I_GPADC
|
|||
select REGMAP_MMIO
|
||||
select REGMAP_IRQ
|
||||
depends on ARCH_SUNXI || COMPILE_TEST
|
||||
depends on !TOUCHSCREEN_SUN4I
|
||||
help
|
||||
Select this to get support for Allwinner SoCs (A10, A13 and A31) ADC.
|
||||
This driver will only map the hardware interrupt and registers, you
|
||||
|
@ -506,17 +507,22 @@ config MFD_KEMPLD
|
|||
device may provide functions like watchdog, GPIO, UART and I2C bus.
|
||||
|
||||
The following modules are supported:
|
||||
* COMe-bBD#
|
||||
* COMe-bBL6
|
||||
* COMe-bHL6
|
||||
* COMe-bSL6
|
||||
* COMe-bIP#
|
||||
* COMe-bKL6
|
||||
* COMe-bPC2 (ETXexpress-PC)
|
||||
* COMe-bSC# (ETXexpress-SC T#)
|
||||
* COMe-cAL6
|
||||
* COMe-cBL6
|
||||
* COMe-cBT6
|
||||
* COMe-cBW6
|
||||
* COMe-cCT6
|
||||
* COMe-cDC2 (microETXexpress-DC)
|
||||
* COMe-cHL6
|
||||
* COMe-cKL6
|
||||
* COMe-cPC2 (microETXexpress-PC)
|
||||
* COMe-cSL6
|
||||
* COMe-mAL10
|
||||
|
@ -714,6 +720,17 @@ config EZX_PCAP
|
|||
This enables the PCAP ASIC present on EZX Phones. This is
|
||||
needed for MMC, TouchScreen, Sound, USB, etc..
|
||||
|
||||
config MFD_CPCAP
|
||||
tristate "Support for Motorola CPCAP"
|
||||
depends on SPI
|
||||
depends on OF || COMPILE_TEST
|
||||
select REGMAP_SPI
|
||||
select REGMAP_IRQ
|
||||
help
|
||||
Say yes here if you want to include driver for CPCAP.
|
||||
It is used on many Motorola phones and tablets as a PMIC.
|
||||
At least Motorola Droid 4 is known to use CPCAP.
|
||||
|
||||
config MFD_VIPERBOARD
|
||||
tristate "Nano River Technologies Viperboard"
|
||||
select MFD_CORE
|
||||
|
|
|
@ -97,6 +97,7 @@ obj-$(CONFIG_MFD_MC13XXX_I2C) += mc13xxx-i2c.o
|
|||
obj-$(CONFIG_MFD_CORE) += mfd-core.o
|
||||
|
||||
obj-$(CONFIG_EZX_PCAP) += ezx-pcap.o
|
||||
obj-$(CONFIG_MFD_CPCAP) += motorola-cpcap.o
|
||||
|
||||
obj-$(CONFIG_MCP) += mcp-core.o
|
||||
obj-$(CONFIG_MCP_SA11X0) += mcp-sa11x0.o
|
||||
|
|
|
@ -656,8 +656,8 @@ static const struct mfd_cell ab8500_devs[] = {
|
|||
.of_compatible = "stericsson,ab8500-regulator",
|
||||
},
|
||||
{
|
||||
.name = "abx500-clk",
|
||||
.of_compatible = "stericsson,abx500-clk",
|
||||
.name = "ab8500-clk",
|
||||
.of_compatible = "stericsson,ab8500-clk",
|
||||
},
|
||||
{
|
||||
.name = "ab8500-gpadc",
|
||||
|
|
|
@ -101,7 +101,7 @@ int ab8500_sysctrl_read(u16 reg, u8 *value)
|
|||
u8 bank;
|
||||
|
||||
if (sysctrl_dev == NULL)
|
||||
return -EINVAL;
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
bank = (reg >> 8);
|
||||
if (!valid_bank(bank))
|
||||
|
@ -117,11 +117,13 @@ int ab8500_sysctrl_write(u16 reg, u8 mask, u8 value)
|
|||
u8 bank;
|
||||
|
||||
if (sysctrl_dev == NULL)
|
||||
return -EINVAL;
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
bank = (reg >> 8);
|
||||
if (!valid_bank(bank))
|
||||
if (!valid_bank(bank)) {
|
||||
pr_err("invalid bank\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return abx500_mask_and_set_register_interruptible(sysctrl_dev, bank,
|
||||
(u8)(reg & 0xFF), mask, value);
|
||||
|
@ -148,9 +150,15 @@ static int ab8500_sysctrl_remove(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id ab8500_sysctrl_match[] = {
|
||||
{ .compatible = "stericsson,ab8500-sysctrl", },
|
||||
{}
|
||||
};
|
||||
|
||||
static struct platform_driver ab8500_sysctrl_driver = {
|
||||
.driver = {
|
||||
.name = "ab8500-sysctrl",
|
||||
.of_match_table = ab8500_sysctrl_match,
|
||||
},
|
||||
.probe = ab8500_sysctrl_probe,
|
||||
.remove = ab8500_sysctrl_remove,
|
||||
|
|
|
@ -26,6 +26,9 @@
|
|||
|
||||
#include "arizona.h"
|
||||
|
||||
#define ARIZONA_AOD_IRQ_INDEX 0
|
||||
#define ARIZONA_MAIN_IRQ_INDEX 1
|
||||
|
||||
static int arizona_map_irq(struct arizona *arizona, int irq)
|
||||
{
|
||||
int ret;
|
||||
|
@ -204,9 +207,10 @@ static const struct irq_domain_ops arizona_domain_ops = {
|
|||
int arizona_irq_init(struct arizona *arizona)
|
||||
{
|
||||
int flags = IRQF_ONESHOT;
|
||||
int ret, i;
|
||||
int ret;
|
||||
const struct regmap_irq_chip *aod, *irq;
|
||||
struct irq_data *irq_data;
|
||||
unsigned int virq;
|
||||
|
||||
arizona->ctrlif_error = true;
|
||||
|
||||
|
@ -318,24 +322,34 @@ int arizona_irq_init(struct arizona *arizona)
|
|||
}
|
||||
|
||||
if (aod) {
|
||||
ret = regmap_add_irq_chip(arizona->regmap,
|
||||
irq_create_mapping(arizona->virq, 0),
|
||||
IRQF_ONESHOT, 0, aod,
|
||||
&arizona->aod_irq_chip);
|
||||
virq = irq_create_mapping(arizona->virq, ARIZONA_AOD_IRQ_INDEX);
|
||||
if (!virq) {
|
||||
dev_err(arizona->dev, "Failed to map AOD IRQs\n");
|
||||
ret = -EINVAL;
|
||||
goto err_domain;
|
||||
}
|
||||
|
||||
ret = regmap_add_irq_chip(arizona->regmap, virq, IRQF_ONESHOT,
|
||||
0, aod, &arizona->aod_irq_chip);
|
||||
if (ret != 0) {
|
||||
dev_err(arizona->dev,
|
||||
"Failed to add AOD IRQs: %d\n", ret);
|
||||
goto err;
|
||||
goto err_map_aod;
|
||||
}
|
||||
}
|
||||
|
||||
ret = regmap_add_irq_chip(arizona->regmap,
|
||||
irq_create_mapping(arizona->virq, 1),
|
||||
IRQF_ONESHOT, 0, irq,
|
||||
&arizona->irq_chip);
|
||||
virq = irq_create_mapping(arizona->virq, ARIZONA_MAIN_IRQ_INDEX);
|
||||
if (!virq) {
|
||||
dev_err(arizona->dev, "Failed to map main IRQs\n");
|
||||
ret = -EINVAL;
|
||||
goto err_aod;
|
||||
}
|
||||
|
||||
ret = regmap_add_irq_chip(arizona->regmap, virq, IRQF_ONESHOT,
|
||||
0, irq, &arizona->irq_chip);
|
||||
if (ret != 0) {
|
||||
dev_err(arizona->dev, "Failed to add main IRQs: %d\n", ret);
|
||||
goto err_aod;
|
||||
goto err_map_main_irq;
|
||||
}
|
||||
|
||||
/* Used to emulate edge trigger and to work around broken pinmux */
|
||||
|
@ -368,9 +382,8 @@ int arizona_irq_init(struct arizona *arizona)
|
|||
}
|
||||
|
||||
/* Make sure the boot done IRQ is unmasked for resumes */
|
||||
i = arizona_map_irq(arizona, ARIZONA_IRQ_BOOT_DONE);
|
||||
ret = request_threaded_irq(i, NULL, arizona_boot_done, IRQF_ONESHOT,
|
||||
"Boot done", arizona);
|
||||
ret = arizona_request_irq(arizona, ARIZONA_IRQ_BOOT_DONE, "Boot done",
|
||||
arizona_boot_done, arizona);
|
||||
if (ret != 0) {
|
||||
dev_err(arizona->dev, "Failed to request boot done %d: %d\n",
|
||||
arizona->irq, ret);
|
||||
|
@ -379,10 +392,9 @@ int arizona_irq_init(struct arizona *arizona)
|
|||
|
||||
/* Handle control interface errors in the core */
|
||||
if (arizona->ctrlif_error) {
|
||||
i = arizona_map_irq(arizona, ARIZONA_IRQ_CTRLIF_ERR);
|
||||
ret = request_threaded_irq(i, NULL, arizona_ctrlif_err,
|
||||
IRQF_ONESHOT,
|
||||
"Control interface error", arizona);
|
||||
ret = arizona_request_irq(arizona, ARIZONA_IRQ_CTRLIF_ERR,
|
||||
"Control interface error",
|
||||
arizona_ctrlif_err, arizona);
|
||||
if (ret != 0) {
|
||||
dev_err(arizona->dev,
|
||||
"Failed to request CTRLIF_ERR %d: %d\n",
|
||||
|
@ -394,29 +406,47 @@ int arizona_irq_init(struct arizona *arizona)
|
|||
return 0;
|
||||
|
||||
err_ctrlif:
|
||||
free_irq(arizona_map_irq(arizona, ARIZONA_IRQ_BOOT_DONE), arizona);
|
||||
arizona_free_irq(arizona, ARIZONA_IRQ_BOOT_DONE, arizona);
|
||||
err_boot_done:
|
||||
free_irq(arizona->irq, arizona);
|
||||
err_main_irq:
|
||||
regmap_del_irq_chip(irq_find_mapping(arizona->virq, 1),
|
||||
regmap_del_irq_chip(irq_find_mapping(arizona->virq,
|
||||
ARIZONA_MAIN_IRQ_INDEX),
|
||||
arizona->irq_chip);
|
||||
err_map_main_irq:
|
||||
irq_dispose_mapping(irq_find_mapping(arizona->virq,
|
||||
ARIZONA_MAIN_IRQ_INDEX));
|
||||
err_aod:
|
||||
regmap_del_irq_chip(irq_find_mapping(arizona->virq, 0),
|
||||
regmap_del_irq_chip(irq_find_mapping(arizona->virq,
|
||||
ARIZONA_AOD_IRQ_INDEX),
|
||||
arizona->aod_irq_chip);
|
||||
err_map_aod:
|
||||
irq_dispose_mapping(irq_find_mapping(arizona->virq,
|
||||
ARIZONA_AOD_IRQ_INDEX));
|
||||
err_domain:
|
||||
irq_domain_remove(arizona->virq);
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int arizona_irq_exit(struct arizona *arizona)
|
||||
{
|
||||
unsigned int virq;
|
||||
|
||||
if (arizona->ctrlif_error)
|
||||
free_irq(arizona_map_irq(arizona, ARIZONA_IRQ_CTRLIF_ERR),
|
||||
arizona);
|
||||
free_irq(arizona_map_irq(arizona, ARIZONA_IRQ_BOOT_DONE), arizona);
|
||||
regmap_del_irq_chip(irq_find_mapping(arizona->virq, 1),
|
||||
arizona->irq_chip);
|
||||
regmap_del_irq_chip(irq_find_mapping(arizona->virq, 0),
|
||||
arizona->aod_irq_chip);
|
||||
arizona_free_irq(arizona, ARIZONA_IRQ_CTRLIF_ERR, arizona);
|
||||
arizona_free_irq(arizona, ARIZONA_IRQ_BOOT_DONE, arizona);
|
||||
|
||||
virq = irq_find_mapping(arizona->virq, ARIZONA_MAIN_IRQ_INDEX);
|
||||
regmap_del_irq_chip(virq, arizona->irq_chip);
|
||||
irq_dispose_mapping(virq);
|
||||
|
||||
virq = irq_find_mapping(arizona->virq, ARIZONA_AOD_IRQ_INDEX);
|
||||
regmap_del_irq_chip(virq, arizona->aod_irq_chip);
|
||||
irq_dispose_mapping(virq);
|
||||
|
||||
irq_domain_remove(arizona->virq);
|
||||
|
||||
free_irq(arizona->irq, arizona);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -17,8 +17,6 @@
|
|||
#include <linux/regmap.h>
|
||||
#include <linux/pm.h>
|
||||
|
||||
struct wm_arizona;
|
||||
|
||||
extern const struct regmap_config wm5102_i2c_regmap;
|
||||
extern const struct regmap_config wm5102_spi_regmap;
|
||||
|
||||
|
|
|
@ -31,6 +31,8 @@
|
|||
|
||||
#define AXP20X_OFF 0x80
|
||||
|
||||
#define AXP806_REG_ADDR_EXT_ADDR_SLAVE_MODE BIT(4)
|
||||
|
||||
static const char * const axp20x_model_names[] = {
|
||||
"AXP152",
|
||||
"AXP202",
|
||||
|
@ -118,7 +120,14 @@ static const struct regmap_range axp288_writeable_ranges[] = {
|
|||
};
|
||||
|
||||
static const struct regmap_range axp288_volatile_ranges[] = {
|
||||
regmap_reg_range(AXP20X_PWR_INPUT_STATUS, AXP288_POWER_REASON),
|
||||
regmap_reg_range(AXP288_BC_GLOBAL, AXP288_BC_GLOBAL),
|
||||
regmap_reg_range(AXP288_BC_DET_STAT, AXP288_BC_DET_STAT),
|
||||
regmap_reg_range(AXP20X_IRQ1_EN, AXP20X_IPSOUT_V_HIGH_L),
|
||||
regmap_reg_range(AXP20X_TIMER_CTRL, AXP20X_TIMER_CTRL),
|
||||
regmap_reg_range(AXP22X_GPIO_STATE, AXP22X_GPIO_STATE),
|
||||
regmap_reg_range(AXP288_RT_BATT_V_H, AXP288_RT_BATT_V_L),
|
||||
regmap_reg_range(AXP20X_FG_RES, AXP288_FG_CC_CAP_REG),
|
||||
};
|
||||
|
||||
static const struct regmap_access_table axp288_writeable_table = {
|
||||
|
@ -207,14 +216,14 @@ static struct resource axp22x_pek_resources[] = {
|
|||
static struct resource axp288_power_button_resources[] = {
|
||||
{
|
||||
.name = "PEK_DBR",
|
||||
.start = AXP288_IRQ_POKN,
|
||||
.end = AXP288_IRQ_POKN,
|
||||
.start = AXP288_IRQ_POKP,
|
||||
.end = AXP288_IRQ_POKP,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
{
|
||||
.name = "PEK_DBF",
|
||||
.start = AXP288_IRQ_POKP,
|
||||
.end = AXP288_IRQ_POKP,
|
||||
.start = AXP288_IRQ_POKN,
|
||||
.end = AXP288_IRQ_POKN,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
@ -407,6 +416,9 @@ static const struct regmap_irq axp288_regmap_irqs[] = {
|
|||
INIT_REGMAP_IRQ(AXP288, VBUS_FALL, 0, 2),
|
||||
INIT_REGMAP_IRQ(AXP288, VBUS_RISE, 0, 3),
|
||||
INIT_REGMAP_IRQ(AXP288, OV, 0, 4),
|
||||
INIT_REGMAP_IRQ(AXP288, FALLING_ALT, 0, 5),
|
||||
INIT_REGMAP_IRQ(AXP288, RISING_ALT, 0, 6),
|
||||
INIT_REGMAP_IRQ(AXP288, OV_ALT, 0, 7),
|
||||
|
||||
INIT_REGMAP_IRQ(AXP288, DONE, 1, 2),
|
||||
INIT_REGMAP_IRQ(AXP288, CHARGING, 1, 3),
|
||||
|
@ -589,7 +601,7 @@ static struct mfd_cell axp20x_cells[] = {
|
|||
},
|
||||
};
|
||||
|
||||
static struct mfd_cell axp22x_cells[] = {
|
||||
static struct mfd_cell axp221_cells[] = {
|
||||
{
|
||||
.name = "axp20x-pek",
|
||||
.num_resources = ARRAY_SIZE(axp22x_pek_resources),
|
||||
|
@ -604,6 +616,21 @@ static struct mfd_cell axp22x_cells[] = {
|
|||
},
|
||||
};
|
||||
|
||||
static struct mfd_cell axp223_cells[] = {
|
||||
{
|
||||
.name = "axp20x-pek",
|
||||
.num_resources = ARRAY_SIZE(axp22x_pek_resources),
|
||||
.resources = axp22x_pek_resources,
|
||||
}, {
|
||||
.name = "axp20x-regulator",
|
||||
}, {
|
||||
.name = "axp20x-usb-power-supply",
|
||||
.of_compatible = "x-powers,axp223-usb-power-supply",
|
||||
.num_resources = ARRAY_SIZE(axp22x_usb_power_supply_resources),
|
||||
.resources = axp22x_usb_power_supply_resources,
|
||||
},
|
||||
};
|
||||
|
||||
static struct mfd_cell axp152_cells[] = {
|
||||
{
|
||||
.name = "axp20x-pek",
|
||||
|
@ -791,9 +818,14 @@ int axp20x_match_device(struct axp20x_dev *axp20x)
|
|||
axp20x->regmap_irq_chip = &axp20x_regmap_irq_chip;
|
||||
break;
|
||||
case AXP221_ID:
|
||||
axp20x->nr_cells = ARRAY_SIZE(axp221_cells);
|
||||
axp20x->cells = axp221_cells;
|
||||
axp20x->regmap_cfg = &axp22x_regmap_config;
|
||||
axp20x->regmap_irq_chip = &axp22x_regmap_irq_chip;
|
||||
break;
|
||||
case AXP223_ID:
|
||||
axp20x->nr_cells = ARRAY_SIZE(axp22x_cells);
|
||||
axp20x->cells = axp22x_cells;
|
||||
axp20x->nr_cells = ARRAY_SIZE(axp223_cells);
|
||||
axp20x->cells = axp223_cells;
|
||||
axp20x->regmap_cfg = &axp22x_regmap_config;
|
||||
axp20x->regmap_irq_chip = &axp22x_regmap_irq_chip;
|
||||
break;
|
||||
|
@ -802,6 +834,7 @@ int axp20x_match_device(struct axp20x_dev *axp20x)
|
|||
axp20x->nr_cells = ARRAY_SIZE(axp288_cells);
|
||||
axp20x->regmap_cfg = &axp288_regmap_config;
|
||||
axp20x->regmap_irq_chip = &axp288_regmap_irq_chip;
|
||||
axp20x->irq_flags = IRQF_TRIGGER_LOW;
|
||||
break;
|
||||
case AXP806_ID:
|
||||
axp20x->nr_cells = ARRAY_SIZE(axp806_cells);
|
||||
|
@ -830,10 +863,33 @@ int axp20x_device_probe(struct axp20x_dev *axp20x)
|
|||
{
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* The AXP806 supports either master/standalone or slave mode.
|
||||
* Slave mode allows sharing the serial bus, even with multiple
|
||||
* AXP806 which all have the same hardware address.
|
||||
*
|
||||
* This is done with extra "serial interface address extension",
|
||||
* or AXP806_BUS_ADDR_EXT, and "register address extension", or
|
||||
* AXP806_REG_ADDR_EXT, registers. The former is read-only, with
|
||||
* 1 bit customizable at the factory, and 1 bit depending on the
|
||||
* state of an external pin. The latter is writable. The device
|
||||
* will only respond to operations to its other registers when
|
||||
* the these device addressing bits (in the upper 4 bits of the
|
||||
* registers) match.
|
||||
*
|
||||
* Since we only support an AXP806 chained to an AXP809 in slave
|
||||
* mode, and there isn't any existing hardware which uses AXP806
|
||||
* in master mode, or has 2 AXP806s in the same system, we can
|
||||
* just program the register address extension to the slave mode
|
||||
* address.
|
||||
*/
|
||||
if (axp20x->variant == AXP806_ID)
|
||||
regmap_write(axp20x->regmap, AXP806_REG_ADDR_EXT,
|
||||
AXP806_REG_ADDR_EXT_ADDR_SLAVE_MODE);
|
||||
|
||||
ret = regmap_add_irq_chip(axp20x->regmap, axp20x->irq,
|
||||
IRQF_ONESHOT | IRQF_SHARED, -1,
|
||||
axp20x->regmap_irq_chip,
|
||||
&axp20x->regmap_irqc);
|
||||
IRQF_ONESHOT | IRQF_SHARED | axp20x->irq_flags,
|
||||
-1, axp20x->regmap_irq_chip, &axp20x->regmap_irqc);
|
||||
if (ret) {
|
||||
dev_err(axp20x->dev, "failed to add irq chip: %d\n", ret);
|
||||
return ret;
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/cros_ec.h>
|
||||
#include <linux/suspend.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#define CROS_EC_DEV_EC_INDEX 0
|
||||
|
@ -65,6 +66,24 @@ static irqreturn_t ec_irq_thread(int irq, void *data)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int cros_ec_sleep_event(struct cros_ec_device *ec_dev, u8 sleep_event)
|
||||
{
|
||||
struct {
|
||||
struct cros_ec_command msg;
|
||||
struct ec_params_host_sleep_event req;
|
||||
} __packed buf;
|
||||
|
||||
memset(&buf, 0, sizeof(buf));
|
||||
|
||||
buf.req.sleep_event = sleep_event;
|
||||
|
||||
buf.msg.command = EC_CMD_HOST_SLEEP_EVENT;
|
||||
buf.msg.version = 0;
|
||||
buf.msg.outsize = sizeof(buf.req);
|
||||
|
||||
return cros_ec_cmd_xfer(ec_dev, &buf.msg);
|
||||
}
|
||||
|
||||
int cros_ec_register(struct cros_ec_device *ec_dev)
|
||||
{
|
||||
struct device *dev = ec_dev->dev;
|
||||
|
@ -136,6 +155,15 @@ int cros_ec_register(struct cros_ec_device *ec_dev)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Clear sleep event - this will fail harmlessly on platforms that
|
||||
* don't implement the sleep event host command.
|
||||
*/
|
||||
err = cros_ec_sleep_event(ec_dev, 0);
|
||||
if (err < 0)
|
||||
dev_dbg(ec_dev->dev, "Error %d clearing sleep event to ec",
|
||||
err);
|
||||
|
||||
dev_info(dev, "Chrome EC device registered\n");
|
||||
|
||||
return 0;
|
||||
|
@ -159,12 +187,24 @@ EXPORT_SYMBOL(cros_ec_remove);
|
|||
int cros_ec_suspend(struct cros_ec_device *ec_dev)
|
||||
{
|
||||
struct device *dev = ec_dev->dev;
|
||||
int ret;
|
||||
u8 sleep_event;
|
||||
|
||||
sleep_event = (!IS_ENABLED(CONFIG_ACPI) || pm_suspend_via_firmware()) ?
|
||||
HOST_SLEEP_EVENT_S3_RESUME :
|
||||
HOST_SLEEP_EVENT_S0IX_RESUME;
|
||||
|
||||
ret = cros_ec_sleep_event(ec_dev, sleep_event);
|
||||
if (ret < 0)
|
||||
dev_dbg(ec_dev->dev, "Error %d sending suspend event to ec",
|
||||
ret);
|
||||
|
||||
if (device_may_wakeup(dev))
|
||||
ec_dev->wake_enabled = !enable_irq_wake(ec_dev->irq);
|
||||
|
||||
disable_irq(ec_dev->irq);
|
||||
ec_dev->was_wake_device = ec_dev->wake_enabled;
|
||||
ec_dev->suspended = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -179,8 +219,21 @@ static void cros_ec_drain_events(struct cros_ec_device *ec_dev)
|
|||
|
||||
int cros_ec_resume(struct cros_ec_device *ec_dev)
|
||||
{
|
||||
int ret;
|
||||
u8 sleep_event;
|
||||
|
||||
ec_dev->suspended = false;
|
||||
enable_irq(ec_dev->irq);
|
||||
|
||||
sleep_event = (!IS_ENABLED(CONFIG_ACPI) || pm_suspend_via_firmware()) ?
|
||||
HOST_SLEEP_EVENT_S3_RESUME :
|
||||
HOST_SLEEP_EVENT_S0IX_RESUME;
|
||||
|
||||
ret = cros_ec_sleep_event(ec_dev, sleep_event);
|
||||
if (ret < 0)
|
||||
dev_dbg(ec_dev->dev, "Error %d sending resume event to ec",
|
||||
ret);
|
||||
|
||||
/*
|
||||
* In some cases, we need to distinguish between events that occur
|
||||
* during suspend if the EC is not a wake source. For example,
|
||||
|
|
|
@ -157,7 +157,22 @@ static const struct pci_device_id intel_lpss_pci_ids[] = {
|
|||
{ PCI_VDEVICE(INTEL, 0x1ac4), (kernel_ulong_t)&bxt_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x1ac6), (kernel_ulong_t)&bxt_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x1aee), (kernel_ulong_t)&bxt_uart_info },
|
||||
|
||||
/* GLK */
|
||||
{ PCI_VDEVICE(INTEL, 0x31ac), (kernel_ulong_t)&bxt_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x31ae), (kernel_ulong_t)&bxt_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x31b0), (kernel_ulong_t)&bxt_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x31b2), (kernel_ulong_t)&bxt_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x31b4), (kernel_ulong_t)&bxt_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x31b6), (kernel_ulong_t)&bxt_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x31b8), (kernel_ulong_t)&bxt_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x31ba), (kernel_ulong_t)&bxt_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x31bc), (kernel_ulong_t)&bxt_uart_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x31be), (kernel_ulong_t)&bxt_uart_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x31c0), (kernel_ulong_t)&bxt_uart_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x31ee), (kernel_ulong_t)&bxt_uart_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x31c2), (kernel_ulong_t)&bxt_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x31c4), (kernel_ulong_t)&bxt_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x31c6), (kernel_ulong_t)&bxt_info },
|
||||
/* APL */
|
||||
{ PCI_VDEVICE(INTEL, 0x5aac), (kernel_ulong_t)&apl_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x5aae), (kernel_ulong_t)&apl_i2c_info },
|
||||
|
|
|
@ -496,6 +496,14 @@ static struct platform_driver kempld_driver = {
|
|||
|
||||
static struct dmi_system_id kempld_dmi_table[] __initdata = {
|
||||
{
|
||||
.ident = "BBD6",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
|
||||
DMI_MATCH(DMI_BOARD_NAME, "COMe-bBD"),
|
||||
},
|
||||
.driver_data = (void *)&kempld_platform_data_generic,
|
||||
.callback = kempld_create_platform_device,
|
||||
}, {
|
||||
.ident = "BBL6",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
|
||||
|
@ -511,6 +519,30 @@ static struct dmi_system_id kempld_dmi_table[] __initdata = {
|
|||
},
|
||||
.driver_data = (void *)&kempld_platform_data_generic,
|
||||
.callback = kempld_create_platform_device,
|
||||
}, {
|
||||
.ident = "BKL6",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
|
||||
DMI_MATCH(DMI_BOARD_NAME, "COMe-bKL6"),
|
||||
},
|
||||
.driver_data = (void *)&kempld_platform_data_generic,
|
||||
.callback = kempld_create_platform_device,
|
||||
}, {
|
||||
.ident = "BSL6",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
|
||||
DMI_MATCH(DMI_BOARD_NAME, "COMe-bSL6"),
|
||||
},
|
||||
.driver_data = (void *)&kempld_platform_data_generic,
|
||||
.callback = kempld_create_platform_device,
|
||||
}, {
|
||||
.ident = "CAL6",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
|
||||
DMI_MATCH(DMI_BOARD_NAME, "COMe-cAL"),
|
||||
},
|
||||
.driver_data = (void *)&kempld_platform_data_generic,
|
||||
.callback = kempld_create_platform_device,
|
||||
}, {
|
||||
.ident = "CBL6",
|
||||
.matches = {
|
||||
|
@ -599,6 +631,14 @@ static struct dmi_system_id kempld_dmi_table[] __initdata = {
|
|||
},
|
||||
.driver_data = (void *)&kempld_platform_data_generic,
|
||||
.callback = kempld_create_platform_device,
|
||||
}, {
|
||||
.ident = "CKL6",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
|
||||
DMI_MATCH(DMI_BOARD_NAME, "COMe-cKL6"),
|
||||
},
|
||||
.driver_data = (void *)&kempld_platform_data_generic,
|
||||
.callback = kempld_create_platform_device,
|
||||
}, {
|
||||
.ident = "CNTG",
|
||||
.matches = {
|
||||
|
|
|
@ -20,10 +20,6 @@
|
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* This driver supports the following I/O Controller hubs:
|
||||
* (See the intel documentation on http://developer.intel.com.)
|
||||
* document number 290655-003, 290677-014: 82801AA (ICH), 82801AB (ICHO)
|
||||
|
@ -45,18 +41,6 @@
|
|||
* document number 322169-001, 322170-003: 5 Series, 3400 Series (PCH)
|
||||
* document number 320066-003, 320257-008: EP80597 (IICH)
|
||||
* document number 324645-001, 324646-001: Cougar Point (CPT)
|
||||
* document number TBD : Patsburg (PBG)
|
||||
* document number TBD : DH89xxCC
|
||||
* document number TBD : Panther Point
|
||||
* document number TBD : Lynx Point
|
||||
* document number TBD : Lynx Point-LP
|
||||
* document number TBD : Wellsburg
|
||||
* document number TBD : Avoton SoC
|
||||
* document number TBD : Coleto Creek
|
||||
* document number TBD : Wildcat Point-LP
|
||||
* document number TBD : 9 Series
|
||||
* document number TBD : Lewisburg
|
||||
* document number TBD : Apollo Lake SoC
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
@ -567,6 +551,7 @@ static struct lpc_ich_info lpc_chipset_info[] = {
|
|||
},
|
||||
[LPC_APL] = {
|
||||
.name = "Apollo Lake SoC",
|
||||
.iTCO_version = 5,
|
||||
.spi_type = INTEL_SPI_BXT,
|
||||
},
|
||||
};
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include <linux/mfd/max77686-private.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
|
||||
static const struct mfd_cell max77686_devs[] = {
|
||||
{ .name = "max77686-pmic", },
|
||||
|
@ -171,11 +172,9 @@ static const struct of_device_id max77686_pmic_dt_match[] = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(of, max77686_pmic_dt_match);
|
||||
|
||||
static int max77686_i2c_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *id)
|
||||
static int max77686_i2c_probe(struct i2c_client *i2c)
|
||||
{
|
||||
struct max77686_dev *max77686 = NULL;
|
||||
const struct of_device_id *match;
|
||||
unsigned int data;
|
||||
int ret = 0;
|
||||
const struct regmap_config *config;
|
||||
|
@ -188,16 +187,8 @@ static int max77686_i2c_probe(struct i2c_client *i2c,
|
|||
if (!max77686)
|
||||
return -ENOMEM;
|
||||
|
||||
if (i2c->dev.of_node) {
|
||||
match = of_match_node(max77686_pmic_dt_match, i2c->dev.of_node);
|
||||
if (!match)
|
||||
return -EINVAL;
|
||||
|
||||
max77686->type = (unsigned long)match->data;
|
||||
} else
|
||||
max77686->type = id->driver_data;
|
||||
|
||||
i2c_set_clientdata(i2c, max77686);
|
||||
max77686->type = (unsigned long)of_device_get_match_data(&i2c->dev);
|
||||
max77686->dev = &i2c->dev;
|
||||
max77686->i2c = i2c;
|
||||
|
||||
|
@ -250,13 +241,6 @@ static int max77686_i2c_probe(struct i2c_client *i2c,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id max77686_i2c_id[] = {
|
||||
{ "max77686", TYPE_MAX77686 },
|
||||
{ "max77802", TYPE_MAX77802 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, max77686_i2c_id);
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int max77686_suspend(struct device *dev)
|
||||
{
|
||||
|
@ -302,8 +286,7 @@ static struct i2c_driver max77686_i2c_driver = {
|
|||
.pm = &max77686_pm,
|
||||
.of_match_table = of_match_ptr(max77686_pmic_dt_match),
|
||||
},
|
||||
.probe = max77686_i2c_probe,
|
||||
.id_table = max77686_i2c_id,
|
||||
.probe_new = max77686_i2c_probe,
|
||||
};
|
||||
|
||||
module_i2c_driver(max77686_i2c_driver);
|
||||
|
|
|
@ -0,0 +1,259 @@
|
|||
/*
|
||||
* Motorola CPCAP PMIC core driver
|
||||
*
|
||||
* Copyright (C) 2016 Tony Lindgren <tony@atomide.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/sysfs.h>
|
||||
|
||||
#include <linux/mfd/motorola-cpcap.h>
|
||||
#include <linux/spi/spi.h>
|
||||
|
||||
#define CPCAP_NR_IRQ_REG_BANKS 6
|
||||
#define CPCAP_NR_IRQ_CHIPS 3
|
||||
|
||||
struct cpcap_ddata {
|
||||
struct spi_device *spi;
|
||||
struct regmap_irq *irqs;
|
||||
struct regmap_irq_chip_data *irqdata[CPCAP_NR_IRQ_CHIPS];
|
||||
const struct regmap_config *regmap_conf;
|
||||
struct regmap *regmap;
|
||||
};
|
||||
|
||||
static int cpcap_check_revision(struct cpcap_ddata *cpcap)
|
||||
{
|
||||
u16 vendor, rev;
|
||||
int ret;
|
||||
|
||||
ret = cpcap_get_vendor(&cpcap->spi->dev, cpcap->regmap, &vendor);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = cpcap_get_revision(&cpcap->spi->dev, cpcap->regmap, &rev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
dev_info(&cpcap->spi->dev, "CPCAP vendor: %s rev: %i.%i (%x)\n",
|
||||
vendor == CPCAP_VENDOR_ST ? "ST" : "TI",
|
||||
CPCAP_REVISION_MAJOR(rev), CPCAP_REVISION_MINOR(rev),
|
||||
rev);
|
||||
|
||||
if (rev < CPCAP_REVISION_2_1) {
|
||||
dev_info(&cpcap->spi->dev,
|
||||
"Please add old CPCAP revision support as needed\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* First two irq chips are the two private macro interrupt chips, the third
|
||||
* irq chip is for register banks 1 - 4 and is available for drivers to use.
|
||||
*/
|
||||
static struct regmap_irq_chip cpcap_irq_chip[CPCAP_NR_IRQ_CHIPS] = {
|
||||
{
|
||||
.name = "cpcap-m2",
|
||||
.num_regs = 1,
|
||||
.status_base = CPCAP_REG_MI1,
|
||||
.ack_base = CPCAP_REG_MI1,
|
||||
.mask_base = CPCAP_REG_MIM1,
|
||||
.use_ack = true,
|
||||
},
|
||||
{
|
||||
.name = "cpcap-m2",
|
||||
.num_regs = 1,
|
||||
.status_base = CPCAP_REG_MI2,
|
||||
.ack_base = CPCAP_REG_MI2,
|
||||
.mask_base = CPCAP_REG_MIM2,
|
||||
.use_ack = true,
|
||||
},
|
||||
{
|
||||
.name = "cpcap1-4",
|
||||
.num_regs = 4,
|
||||
.status_base = CPCAP_REG_INT1,
|
||||
.ack_base = CPCAP_REG_INT1,
|
||||
.mask_base = CPCAP_REG_INTM1,
|
||||
.type_base = CPCAP_REG_INTS1,
|
||||
.use_ack = true,
|
||||
},
|
||||
};
|
||||
|
||||
static void cpcap_init_one_regmap_irq(struct cpcap_ddata *cpcap,
|
||||
struct regmap_irq *rirq,
|
||||
int irq_base, int irq)
|
||||
{
|
||||
unsigned int reg_offset;
|
||||
unsigned int bit, mask;
|
||||
|
||||
reg_offset = irq - irq_base;
|
||||
reg_offset /= cpcap->regmap_conf->val_bits;
|
||||
reg_offset *= cpcap->regmap_conf->reg_stride;
|
||||
|
||||
bit = irq % cpcap->regmap_conf->val_bits;
|
||||
mask = (1 << bit);
|
||||
|
||||
rirq->reg_offset = reg_offset;
|
||||
rirq->mask = mask;
|
||||
}
|
||||
|
||||
static int cpcap_init_irq_chip(struct cpcap_ddata *cpcap, int irq_chip,
|
||||
int irq_start, int nr_irqs)
|
||||
{
|
||||
struct regmap_irq_chip *chip = &cpcap_irq_chip[irq_chip];
|
||||
int i, ret;
|
||||
|
||||
for (i = irq_start; i < irq_start + nr_irqs; i++) {
|
||||
struct regmap_irq *rirq = &cpcap->irqs[i];
|
||||
|
||||
cpcap_init_one_regmap_irq(cpcap, rirq, irq_start, i);
|
||||
}
|
||||
chip->irqs = &cpcap->irqs[irq_start];
|
||||
chip->num_irqs = nr_irqs;
|
||||
chip->irq_drv_data = cpcap;
|
||||
|
||||
ret = devm_regmap_add_irq_chip(&cpcap->spi->dev, cpcap->regmap,
|
||||
cpcap->spi->irq,
|
||||
IRQF_TRIGGER_RISING |
|
||||
IRQF_SHARED, -1,
|
||||
chip, &cpcap->irqdata[irq_chip]);
|
||||
if (ret) {
|
||||
dev_err(&cpcap->spi->dev, "could not add irq chip %i: %i\n",
|
||||
irq_chip, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cpcap_init_irq(struct cpcap_ddata *cpcap)
|
||||
{
|
||||
int ret;
|
||||
|
||||
cpcap->irqs = devm_kzalloc(&cpcap->spi->dev,
|
||||
sizeof(*cpcap->irqs) *
|
||||
CPCAP_NR_IRQ_REG_BANKS *
|
||||
cpcap->regmap_conf->val_bits,
|
||||
GFP_KERNEL);
|
||||
if (!cpcap->irqs)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = cpcap_init_irq_chip(cpcap, 0, 0, 16);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = cpcap_init_irq_chip(cpcap, 1, 16, 16);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = cpcap_init_irq_chip(cpcap, 2, 32, 64);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
enable_irq_wake(cpcap->spi->irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id cpcap_of_match[] = {
|
||||
{ .compatible = "motorola,cpcap", },
|
||||
{ .compatible = "st,6556002", },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, cpcap_of_match);
|
||||
|
||||
static const struct regmap_config cpcap_regmap_config = {
|
||||
.reg_bits = 16,
|
||||
.reg_stride = 4,
|
||||
.pad_bits = 0,
|
||||
.val_bits = 16,
|
||||
.write_flag_mask = 0x8000,
|
||||
.max_register = CPCAP_REG_ST_TEST2,
|
||||
.cache_type = REGCACHE_NONE,
|
||||
.reg_format_endian = REGMAP_ENDIAN_LITTLE,
|
||||
.val_format_endian = REGMAP_ENDIAN_LITTLE,
|
||||
};
|
||||
|
||||
static int cpcap_probe(struct spi_device *spi)
|
||||
{
|
||||
const struct of_device_id *match;
|
||||
struct cpcap_ddata *cpcap;
|
||||
int ret;
|
||||
|
||||
match = of_match_device(of_match_ptr(cpcap_of_match), &spi->dev);
|
||||
if (!match)
|
||||
return -ENODEV;
|
||||
|
||||
cpcap = devm_kzalloc(&spi->dev, sizeof(*cpcap), GFP_KERNEL);
|
||||
if (!cpcap)
|
||||
return -ENOMEM;
|
||||
|
||||
cpcap->spi = spi;
|
||||
spi_set_drvdata(spi, cpcap);
|
||||
|
||||
spi->bits_per_word = 16;
|
||||
spi->mode = SPI_MODE_0 | SPI_CS_HIGH;
|
||||
|
||||
ret = spi_setup(spi);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
cpcap->regmap_conf = &cpcap_regmap_config;
|
||||
cpcap->regmap = devm_regmap_init_spi(spi, &cpcap_regmap_config);
|
||||
if (IS_ERR(cpcap->regmap)) {
|
||||
ret = PTR_ERR(cpcap->regmap);
|
||||
dev_err(&cpcap->spi->dev, "Failed to initialize regmap: %d\n",
|
||||
ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = cpcap_check_revision(cpcap);
|
||||
if (ret) {
|
||||
dev_err(&cpcap->spi->dev, "Failed to detect CPCAP: %i\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = cpcap_init_irq(cpcap);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return of_platform_populate(spi->dev.of_node, NULL, NULL,
|
||||
&cpcap->spi->dev);
|
||||
}
|
||||
|
||||
static int cpcap_remove(struct spi_device *pdev)
|
||||
{
|
||||
struct cpcap_ddata *cpcap = spi_get_drvdata(pdev);
|
||||
|
||||
of_platform_depopulate(&cpcap->spi->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct spi_driver cpcap_driver = {
|
||||
.driver = {
|
||||
.name = "cpcap-core",
|
||||
.of_match_table = cpcap_of_match,
|
||||
},
|
||||
.probe = cpcap_probe,
|
||||
.remove = cpcap_remove,
|
||||
};
|
||||
module_spi_driver(cpcap_driver);
|
||||
|
||||
MODULE_ALIAS("platform:cpcap");
|
||||
MODULE_DESCRIPTION("CPCAP driver");
|
||||
MODULE_AUTHOR("Tony Lindgren <tony@atomide.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -48,6 +48,10 @@ static const struct mfd_cell mt6323_devs[] = {
|
|||
.name = "mt6323-regulator",
|
||||
.of_compatible = "mediatek,mt6323-regulator"
|
||||
},
|
||||
{
|
||||
.name = "mt6323-led",
|
||||
.of_compatible = "mediatek,mt6323-led"
|
||||
},
|
||||
};
|
||||
|
||||
static const struct mfd_cell mt6397_devs[] = {
|
||||
|
|
|
@ -247,7 +247,7 @@ static const struct regmap_irq rk818_irqs[] = {
|
|||
},
|
||||
};
|
||||
|
||||
static struct regmap_irq_chip rk808_irq_chip = {
|
||||
static const struct regmap_irq_chip rk808_irq_chip = {
|
||||
.name = "rk808",
|
||||
.irqs = rk808_irqs,
|
||||
.num_irqs = ARRAY_SIZE(rk808_irqs),
|
||||
|
@ -259,7 +259,7 @@ static struct regmap_irq_chip rk808_irq_chip = {
|
|||
.init_ack_masked = true,
|
||||
};
|
||||
|
||||
static struct regmap_irq_chip rk818_irq_chip = {
|
||||
static const struct regmap_irq_chip rk818_irq_chip = {
|
||||
.name = "rk818",
|
||||
.irqs = rk818_irqs,
|
||||
.num_irqs = ARRAY_SIZE(rk818_irqs),
|
||||
|
|
|
@ -12,6 +12,9 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
#define SUN8I_CODEC_ANALOG_BASE 0x1c0
|
||||
#define SUN8I_CODEC_ANALOG_SIZE 0x4
|
||||
|
||||
struct prcm_data {
|
||||
int nsubdevs;
|
||||
const struct mfd_cell *subdevs;
|
||||
|
@ -57,6 +60,10 @@ static const struct resource sun6i_a31_apb0_rstc_res[] = {
|
|||
},
|
||||
};
|
||||
|
||||
static const struct resource sun8i_codec_analog_res[] = {
|
||||
DEFINE_RES_MEM(SUN8I_CODEC_ANALOG_BASE, SUN8I_CODEC_ANALOG_SIZE),
|
||||
};
|
||||
|
||||
static const struct mfd_cell sun6i_a31_prcm_subdevs[] = {
|
||||
{
|
||||
.name = "sun6i-a31-ar100-clk",
|
||||
|
@ -109,6 +116,12 @@ static const struct mfd_cell sun8i_a23_prcm_subdevs[] = {
|
|||
.num_resources = ARRAY_SIZE(sun6i_a31_apb0_rstc_res),
|
||||
.resources = sun6i_a31_apb0_rstc_res,
|
||||
},
|
||||
{
|
||||
.name = "sun8i-codec-analog",
|
||||
.of_compatible = "allwinner,sun8i-a23-codec-analog",
|
||||
.num_resources = ARRAY_SIZE(sun8i_codec_analog_res),
|
||||
.resources = sun8i_codec_analog_res,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct prcm_data sun6i_a31_prcm_data = {
|
||||
|
|
|
@ -27,6 +27,7 @@ static const struct of_device_id tps65912_i2c_of_match_table[] = {
|
|||
{ .compatible = "ti,tps65912", },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, tps65912_i2c_of_match_table);
|
||||
|
||||
static int tps65912_i2c_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *ids)
|
||||
|
|
|
@ -447,6 +447,11 @@ static int get_next_event(struct cros_ec_device *ec_dev)
|
|||
struct cros_ec_command *msg = (struct cros_ec_command *)&buffer;
|
||||
int ret;
|
||||
|
||||
if (ec_dev->suspended) {
|
||||
dev_dbg(ec_dev->dev, "Device suspended.\n");
|
||||
return -EHOSTDOWN;
|
||||
}
|
||||
|
||||
msg->version = 0;
|
||||
msg->command = EC_CMD_GET_NEXT_EVENT;
|
||||
msg->insize = sizeof(ec_dev->event_data);
|
||||
|
|
|
@ -45,7 +45,7 @@ enum abx500_adc_therm {
|
|||
* struct abx500_res_to_temp - defines one point in a temp to res curve. To
|
||||
* be used in battery packs that combines the identification resistor with a
|
||||
* NTC resistor.
|
||||
* @temp: battery pack temperature in Celcius
|
||||
* @temp: battery pack temperature in Celsius
|
||||
* @resist: NTC resistor net total resistance
|
||||
*/
|
||||
struct abx500_res_to_temp {
|
||||
|
|
|
@ -279,7 +279,7 @@ enum bup_vch_sel {
|
|||
* struct res_to_temp - defines one point in a temp to res curve. To
|
||||
* be used in battery packs that combines the identification resistor with a
|
||||
* NTC resistor.
|
||||
* @temp: battery pack temperature in Celcius
|
||||
* @temp: battery pack temperature in Celsius
|
||||
* @resist: NTC resistor net total resistance
|
||||
*/
|
||||
struct res_to_temp {
|
||||
|
@ -290,7 +290,7 @@ struct res_to_temp {
|
|||
/**
|
||||
* struct batres_vs_temp - defines one point in a temp vs battery internal
|
||||
* resistance curve.
|
||||
* @temp: battery pack temperature in Celcius
|
||||
* @temp: battery pack temperature in Celsius
|
||||
* @resist: battery internal reistance in mOhm
|
||||
*/
|
||||
struct batres_vs_temp {
|
||||
|
|
|
@ -235,10 +235,20 @@ enum axp20x_variants {
|
|||
#define AXP22X_BATLOW_THRES1 0xe6
|
||||
|
||||
/* AXP288 specific registers */
|
||||
#define AXP288_POWER_REASON 0x02
|
||||
#define AXP288_BC_GLOBAL 0x2c
|
||||
#define AXP288_BC_VBUS_CNTL 0x2d
|
||||
#define AXP288_BC_USB_STAT 0x2e
|
||||
#define AXP288_BC_DET_STAT 0x2f
|
||||
#define AXP288_PMIC_ADC_H 0x56
|
||||
#define AXP288_PMIC_ADC_L 0x57
|
||||
#define AXP288_TS_ADC_H 0x58
|
||||
#define AXP288_TS_ADC_L 0x59
|
||||
#define AXP288_GP_ADC_H 0x5a
|
||||
#define AXP288_GP_ADC_L 0x5b
|
||||
#define AXP288_ADC_TS_PIN_CTRL 0x84
|
||||
#define AXP288_PMIC_ADC_EN 0x84
|
||||
#define AXP288_RT_BATT_V_H 0xa0
|
||||
#define AXP288_RT_BATT_V_L 0xa1
|
||||
|
||||
/* Fuel Gauge */
|
||||
#define AXP288_FG_RDC1_REG 0xba
|
||||
|
@ -515,14 +525,10 @@ enum axp809_irqs {
|
|||
AXP809_IRQ_GPIO0_INPUT,
|
||||
};
|
||||
|
||||
#define AXP288_TS_ADC_H 0x58
|
||||
#define AXP288_TS_ADC_L 0x59
|
||||
#define AXP288_GP_ADC_H 0x5a
|
||||
#define AXP288_GP_ADC_L 0x5b
|
||||
|
||||
struct axp20x_dev {
|
||||
struct device *dev;
|
||||
int irq;
|
||||
unsigned long irq_flags;
|
||||
struct regmap *regmap;
|
||||
struct regmap_irq_chip_data *regmap_irqc;
|
||||
long variant;
|
||||
|
@ -582,7 +588,7 @@ int axp20x_match_device(struct axp20x_dev *axp20x);
|
|||
int axp20x_device_probe(struct axp20x_dev *axp20x);
|
||||
|
||||
/**
|
||||
* axp20x_device_probe(): Remove a axp20x device
|
||||
* axp20x_device_remove(): Remove a axp20x device
|
||||
*
|
||||
* @axp20x: axp20x device to remove
|
||||
*
|
||||
|
|
|
@ -103,6 +103,7 @@ struct cros_ec_command {
|
|||
* @din_size: size of din buffer to allocate (zero to use static din)
|
||||
* @dout_size: size of dout buffer to allocate (zero to use static dout)
|
||||
* @wake_enabled: true if this device can wake the system from sleep
|
||||
* @suspended: true if this device had been suspended
|
||||
* @cmd_xfer: send command to EC and get response
|
||||
* Returns the number of bytes received if the communication succeeded, but
|
||||
* that doesn't mean the EC was happy with the command. The caller
|
||||
|
@ -136,6 +137,7 @@ struct cros_ec_device {
|
|||
int din_size;
|
||||
int dout_size;
|
||||
bool wake_enabled;
|
||||
bool suspended;
|
||||
int (*cmd_xfer)(struct cros_ec_device *ec,
|
||||
struct cros_ec_command *msg);
|
||||
int (*pkt_xfer)(struct cros_ec_device *ec,
|
||||
|
|
|
@ -1840,18 +1840,69 @@ struct ec_response_tmp006_get_raw {
|
|||
*
|
||||
* Returns raw data for keyboard cols; see ec_response_mkbp_info.cols for
|
||||
* expected response size.
|
||||
*
|
||||
* NOTE: This has been superseded by EC_CMD_MKBP_GET_NEXT_EVENT. If you wish
|
||||
* to obtain the instantaneous state, use EC_CMD_MKBP_INFO with the type
|
||||
* EC_MKBP_INFO_CURRENT and event EC_MKBP_EVENT_KEY_MATRIX.
|
||||
*/
|
||||
#define EC_CMD_MKBP_STATE 0x60
|
||||
|
||||
/* Provide information about the matrix : number of rows and columns */
|
||||
/*
|
||||
* Provide information about various MKBP things. See enum ec_mkbp_info_type.
|
||||
*/
|
||||
#define EC_CMD_MKBP_INFO 0x61
|
||||
|
||||
struct ec_response_mkbp_info {
|
||||
uint32_t rows;
|
||||
uint32_t cols;
|
||||
uint8_t switches;
|
||||
/* Formerly "switches", which was 0. */
|
||||
uint8_t reserved;
|
||||
} __packed;
|
||||
|
||||
struct ec_params_mkbp_info {
|
||||
uint8_t info_type;
|
||||
uint8_t event_type;
|
||||
} __packed;
|
||||
|
||||
enum ec_mkbp_info_type {
|
||||
/*
|
||||
* Info about the keyboard matrix: number of rows and columns.
|
||||
*
|
||||
* Returns struct ec_response_mkbp_info.
|
||||
*/
|
||||
EC_MKBP_INFO_KBD = 0,
|
||||
|
||||
/*
|
||||
* For buttons and switches, info about which specifically are
|
||||
* supported. event_type must be set to one of the values in enum
|
||||
* ec_mkbp_event.
|
||||
*
|
||||
* For EC_MKBP_EVENT_BUTTON and EC_MKBP_EVENT_SWITCH, returns a 4 byte
|
||||
* bitmask indicating which buttons or switches are present. See the
|
||||
* bit inidices below.
|
||||
*/
|
||||
EC_MKBP_INFO_SUPPORTED = 1,
|
||||
|
||||
/*
|
||||
* Instantaneous state of buttons and switches.
|
||||
*
|
||||
* event_type must be set to one of the values in enum ec_mkbp_event.
|
||||
*
|
||||
* For EC_MKBP_EVENT_KEY_MATRIX, returns uint8_t key_matrix[13]
|
||||
* indicating the current state of the keyboard matrix.
|
||||
*
|
||||
* For EC_MKBP_EVENT_HOST_EVENT, return uint32_t host_event, the raw
|
||||
* event state.
|
||||
*
|
||||
* For EC_MKBP_EVENT_BUTTON, returns uint32_t buttons, indicating the
|
||||
* state of supported buttons.
|
||||
*
|
||||
* For EC_MKBP_EVENT_SWITCH, returns uint32_t switches, indicating the
|
||||
* state of supported switches.
|
||||
*/
|
||||
EC_MKBP_INFO_CURRENT = 2,
|
||||
};
|
||||
|
||||
/* Simulate key press */
|
||||
#define EC_CMD_MKBP_SIMULATE_KEY 0x62
|
||||
|
||||
|
@ -1984,6 +2035,12 @@ enum ec_mkbp_event {
|
|||
/* New Sensor FIFO data. The event data is fifo_info structure. */
|
||||
EC_MKBP_EVENT_SENSOR_FIFO = 2,
|
||||
|
||||
/* The state of the non-matrixed buttons have changed. */
|
||||
EC_MKBP_EVENT_BUTTON = 3,
|
||||
|
||||
/* The state of the switches have changed. */
|
||||
EC_MKBP_EVENT_SWITCH = 4,
|
||||
|
||||
/* Number of MKBP events */
|
||||
EC_MKBP_EVENT_COUNT,
|
||||
};
|
||||
|
@ -1993,6 +2050,9 @@ union ec_response_get_next_data {
|
|||
|
||||
/* Unaligned */
|
||||
uint32_t host_event;
|
||||
|
||||
uint32_t buttons;
|
||||
uint32_t switches;
|
||||
} __packed;
|
||||
|
||||
struct ec_response_get_next_event {
|
||||
|
@ -2001,6 +2061,16 @@ struct ec_response_get_next_event {
|
|||
union ec_response_get_next_data data;
|
||||
} __packed;
|
||||
|
||||
/* Bit indices for buttons and switches.*/
|
||||
/* Buttons */
|
||||
#define EC_MKBP_POWER_BUTTON 0
|
||||
#define EC_MKBP_VOL_UP 1
|
||||
#define EC_MKBP_VOL_DOWN 2
|
||||
|
||||
/* Switches */
|
||||
#define EC_MKBP_LID_OPEN 0
|
||||
#define EC_MKBP_TABLET_MODE 1
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Temperature sensor commands */
|
||||
|
||||
|
@ -2478,6 +2548,20 @@ struct ec_params_ext_power_current_limit {
|
|||
uint32_t limit; /* in mA */
|
||||
} __packed;
|
||||
|
||||
/* Inform the EC when entering a sleep state */
|
||||
#define EC_CMD_HOST_SLEEP_EVENT 0xa9
|
||||
|
||||
enum host_sleep_event {
|
||||
HOST_SLEEP_EVENT_S3_SUSPEND = 1,
|
||||
HOST_SLEEP_EVENT_S3_RESUME = 2,
|
||||
HOST_SLEEP_EVENT_S0IX_SUSPEND = 3,
|
||||
HOST_SLEEP_EVENT_S0IX_RESUME = 4
|
||||
};
|
||||
|
||||
struct ec_params_host_sleep_event {
|
||||
uint8_t sleep_event;
|
||||
} __packed;
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Smart battery pass-through */
|
||||
|
||||
|
|
|
@ -0,0 +1,292 @@
|
|||
/*
|
||||
* The register defines are based on earlier cpcap.h in Motorola Linux kernel
|
||||
* tree.
|
||||
*
|
||||
* Copyright (C) 2007-2009 Motorola, Inc.
|
||||
*
|
||||
* Rewritten for the real register offsets instead of enumeration
|
||||
* to make the defines usable with Linux kernel regmap support
|
||||
*
|
||||
* Copyright (C) 2016 Tony Lindgren <tony@atomide.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#define CPCAP_VENDOR_ST 0
|
||||
#define CPCAP_VENDOR_TI 1
|
||||
|
||||
#define CPCAP_REVISION_MAJOR(r) (((r) >> 4) + 1)
|
||||
#define CPCAP_REVISION_MINOR(r) ((r) & 0xf)
|
||||
|
||||
#define CPCAP_REVISION_1_0 0x08
|
||||
#define CPCAP_REVISION_1_1 0x09
|
||||
#define CPCAP_REVISION_2_0 0x10
|
||||
#define CPCAP_REVISION_2_1 0x11
|
||||
|
||||
/* CPCAP registers */
|
||||
#define CPCAP_REG_INT1 0x0000 /* Interrupt 1 */
|
||||
#define CPCAP_REG_INT2 0x0004 /* Interrupt 2 */
|
||||
#define CPCAP_REG_INT3 0x0008 /* Interrupt 3 */
|
||||
#define CPCAP_REG_INT4 0x000c /* Interrupt 4 */
|
||||
#define CPCAP_REG_INTM1 0x0010 /* Interrupt Mask 1 */
|
||||
#define CPCAP_REG_INTM2 0x0014 /* Interrupt Mask 2 */
|
||||
#define CPCAP_REG_INTM3 0x0018 /* Interrupt Mask 3 */
|
||||
#define CPCAP_REG_INTM4 0x001c /* Interrupt Mask 4 */
|
||||
#define CPCAP_REG_INTS1 0x0020 /* Interrupt Sense 1 */
|
||||
#define CPCAP_REG_INTS2 0x0024 /* Interrupt Sense 2 */
|
||||
#define CPCAP_REG_INTS3 0x0028 /* Interrupt Sense 3 */
|
||||
#define CPCAP_REG_INTS4 0x002c /* Interrupt Sense 4 */
|
||||
#define CPCAP_REG_ASSIGN1 0x0030 /* Resource Assignment 1 */
|
||||
#define CPCAP_REG_ASSIGN2 0x0034 /* Resource Assignment 2 */
|
||||
#define CPCAP_REG_ASSIGN3 0x0038 /* Resource Assignment 3 */
|
||||
#define CPCAP_REG_ASSIGN4 0x003c /* Resource Assignment 4 */
|
||||
#define CPCAP_REG_ASSIGN5 0x0040 /* Resource Assignment 5 */
|
||||
#define CPCAP_REG_ASSIGN6 0x0044 /* Resource Assignment 6 */
|
||||
#define CPCAP_REG_VERSC1 0x0048 /* Version Control 1 */
|
||||
#define CPCAP_REG_VERSC2 0x004c /* Version Control 2 */
|
||||
|
||||
#define CPCAP_REG_MI1 0x0200 /* Macro Interrupt 1 */
|
||||
#define CPCAP_REG_MIM1 0x0204 /* Macro Interrupt Mask 1 */
|
||||
#define CPCAP_REG_MI2 0x0208 /* Macro Interrupt 2 */
|
||||
#define CPCAP_REG_MIM2 0x020c /* Macro Interrupt Mask 2 */
|
||||
#define CPCAP_REG_UCC1 0x0210 /* UC Control 1 */
|
||||
#define CPCAP_REG_UCC2 0x0214 /* UC Control 2 */
|
||||
|
||||
#define CPCAP_REG_PC1 0x021c /* Power Cut 1 */
|
||||
#define CPCAP_REG_PC2 0x0220 /* Power Cut 2 */
|
||||
#define CPCAP_REG_BPEOL 0x0224 /* BP and EOL */
|
||||
#define CPCAP_REG_PGC 0x0228 /* Power Gate and Control */
|
||||
#define CPCAP_REG_MT1 0x022c /* Memory Transfer 1 */
|
||||
#define CPCAP_REG_MT2 0x0230 /* Memory Transfer 2 */
|
||||
#define CPCAP_REG_MT3 0x0234 /* Memory Transfer 3 */
|
||||
#define CPCAP_REG_PF 0x0238 /* Print Format */
|
||||
|
||||
#define CPCAP_REG_SCC 0x0400 /* System Clock Control */
|
||||
#define CPCAP_REG_SW1 0x0404 /* Stop Watch 1 */
|
||||
#define CPCAP_REG_SW2 0x0408 /* Stop Watch 2 */
|
||||
#define CPCAP_REG_UCTM 0x040c /* UC Turbo Mode */
|
||||
#define CPCAP_REG_TOD1 0x0410 /* Time of Day 1 */
|
||||
#define CPCAP_REG_TOD2 0x0414 /* Time of Day 2 */
|
||||
#define CPCAP_REG_TODA1 0x0418 /* Time of Day Alarm 1 */
|
||||
#define CPCAP_REG_TODA2 0x041c /* Time of Day Alarm 2 */
|
||||
#define CPCAP_REG_DAY 0x0420 /* Day */
|
||||
#define CPCAP_REG_DAYA 0x0424 /* Day Alarm */
|
||||
#define CPCAP_REG_VAL1 0x0428 /* Validity 1 */
|
||||
#define CPCAP_REG_VAL2 0x042c /* Validity 2 */
|
||||
|
||||
#define CPCAP_REG_SDVSPLL 0x0600 /* Switcher DVS and PLL */
|
||||
#define CPCAP_REG_SI2CC1 0x0604 /* Switcher I2C Control 1 */
|
||||
#define CPCAP_REG_Si2CC2 0x0608 /* Switcher I2C Control 2 */
|
||||
#define CPCAP_REG_S1C1 0x060c /* Switcher 1 Control 1 */
|
||||
#define CPCAP_REG_S1C2 0x0610 /* Switcher 1 Control 2 */
|
||||
#define CPCAP_REG_S2C1 0x0614 /* Switcher 2 Control 1 */
|
||||
#define CPCAP_REG_S2C2 0x0618 /* Switcher 2 Control 2 */
|
||||
#define CPCAP_REG_S3C 0x061c /* Switcher 3 Control */
|
||||
#define CPCAP_REG_S4C1 0x0620 /* Switcher 4 Control 1 */
|
||||
#define CPCAP_REG_S4C2 0x0624 /* Switcher 4 Control 2 */
|
||||
#define CPCAP_REG_S5C 0x0628 /* Switcher 5 Control */
|
||||
#define CPCAP_REG_S6C 0x062c /* Switcher 6 Control */
|
||||
#define CPCAP_REG_VCAMC 0x0630 /* VCAM Control */
|
||||
#define CPCAP_REG_VCSIC 0x0634 /* VCSI Control */
|
||||
#define CPCAP_REG_VDACC 0x0638 /* VDAC Control */
|
||||
#define CPCAP_REG_VDIGC 0x063c /* VDIG Control */
|
||||
#define CPCAP_REG_VFUSEC 0x0640 /* VFUSE Control */
|
||||
#define CPCAP_REG_VHVIOC 0x0644 /* VHVIO Control */
|
||||
#define CPCAP_REG_VSDIOC 0x0648 /* VSDIO Control */
|
||||
#define CPCAP_REG_VPLLC 0x064c /* VPLL Control */
|
||||
#define CPCAP_REG_VRF1C 0x0650 /* VRF1 Control */
|
||||
#define CPCAP_REG_VRF2C 0x0654 /* VRF2 Control */
|
||||
#define CPCAP_REG_VRFREFC 0x0658 /* VRFREF Control */
|
||||
#define CPCAP_REG_VWLAN1C 0x065c /* VWLAN1 Control */
|
||||
#define CPCAP_REG_VWLAN2C 0x0660 /* VWLAN2 Control */
|
||||
#define CPCAP_REG_VSIMC 0x0664 /* VSIM Control */
|
||||
#define CPCAP_REG_VVIBC 0x0668 /* VVIB Control */
|
||||
#define CPCAP_REG_VUSBC 0x066c /* VUSB Control */
|
||||
#define CPCAP_REG_VUSBINT1C 0x0670 /* VUSBINT1 Control */
|
||||
#define CPCAP_REG_VUSBINT2C 0x0674 /* VUSBINT2 Control */
|
||||
#define CPCAP_REG_URT 0x0678 /* Useroff Regulator Trigger */
|
||||
#define CPCAP_REG_URM1 0x067c /* Useroff Regulator Mask 1 */
|
||||
#define CPCAP_REG_URM2 0x0680 /* Useroff Regulator Mask 2 */
|
||||
|
||||
#define CPCAP_REG_VAUDIOC 0x0800 /* VAUDIO Control */
|
||||
#define CPCAP_REG_CC 0x0804 /* Codec Control */
|
||||
#define CPCAP_REG_CDI 0x0808 /* Codec Digital Interface */
|
||||
#define CPCAP_REG_SDAC 0x080c /* Stereo DAC */
|
||||
#define CPCAP_REG_SDACDI 0x0810 /* Stereo DAC Digital Interface */
|
||||
#define CPCAP_REG_TXI 0x0814 /* TX Inputs */
|
||||
#define CPCAP_REG_TXMP 0x0818 /* TX MIC PGA's */
|
||||
#define CPCAP_REG_RXOA 0x081c /* RX Output Amplifiers */
|
||||
#define CPCAP_REG_RXVC 0x0820 /* RX Volume Control */
|
||||
#define CPCAP_REG_RXCOA 0x0824 /* RX Codec to Output Amps */
|
||||
#define CPCAP_REG_RXSDOA 0x0828 /* RX Stereo DAC to Output Amps */
|
||||
#define CPCAP_REG_RXEPOA 0x082c /* RX External PGA to Output Amps */
|
||||
#define CPCAP_REG_RXLL 0x0830 /* RX Low Latency */
|
||||
#define CPCAP_REG_A2LA 0x0834 /* A2 Loudspeaker Amplifier */
|
||||
#define CPCAP_REG_MIPIS1 0x0838 /* MIPI Slimbus 1 */
|
||||
#define CPCAP_REG_MIPIS2 0x083c /* MIPI Slimbus 2 */
|
||||
#define CPCAP_REG_MIPIS3 0x0840 /* MIPI Slimbus 3. */
|
||||
#define CPCAP_REG_LVAB 0x0844 /* LMR Volume and A4 Balanced. */
|
||||
|
||||
#define CPCAP_REG_CCC1 0x0a00 /* Coulomb Counter Control 1 */
|
||||
#define CPCAP_REG_CRM 0x0a04 /* Charger and Reverse Mode */
|
||||
#define CPCAP_REG_CCCC2 0x0a08 /* Coincell and Coulomb Ctr Ctrl 2 */
|
||||
#define CPCAP_REG_CCS1 0x0a0c /* Coulomb Counter Sample 1 */
|
||||
#define CPCAP_REG_CCS2 0x0a10 /* Coulomb Counter Sample 2 */
|
||||
#define CPCAP_REG_CCA1 0x0a14 /* Coulomb Counter Accumulator 1 */
|
||||
#define CPCAP_REG_CCA2 0x0a18 /* Coulomb Counter Accumulator 2 */
|
||||
#define CPCAP_REG_CCM 0x0a1c /* Coulomb Counter Mode */
|
||||
#define CPCAP_REG_CCO 0x0a20 /* Coulomb Counter Offset */
|
||||
#define CPCAP_REG_CCI 0x0a24 /* Coulomb Counter Integrator */
|
||||
|
||||
#define CPCAP_REG_ADCC1 0x0c00 /* A/D Converter Configuration 1 */
|
||||
#define CPCAP_REG_ADCC2 0x0c04 /* A/D Converter Configuration 2 */
|
||||
#define CPCAP_REG_ADCD0 0x0c08 /* A/D Converter Data 0 */
|
||||
#define CPCAP_REG_ADCD1 0x0c0c /* A/D Converter Data 1 */
|
||||
#define CPCAP_REG_ADCD2 0x0c10 /* A/D Converter Data 2 */
|
||||
#define CPCAP_REG_ADCD3 0x0c14 /* A/D Converter Data 3 */
|
||||
#define CPCAP_REG_ADCD4 0x0c18 /* A/D Converter Data 4 */
|
||||
#define CPCAP_REG_ADCD5 0x0c1c /* A/D Converter Data 5 */
|
||||
#define CPCAP_REG_ADCD6 0x0c20 /* A/D Converter Data 6 */
|
||||
#define CPCAP_REG_ADCD7 0x0c24 /* A/D Converter Data 7 */
|
||||
#define CPCAP_REG_ADCAL1 0x0c28 /* A/D Converter Calibration 1 */
|
||||
#define CPCAP_REG_ADCAL2 0x0c2c /* A/D Converter Calibration 2 */
|
||||
|
||||
#define CPCAP_REG_USBC1 0x0e00 /* USB Control 1 */
|
||||
#define CPCAP_REG_USBC2 0x0e04 /* USB Control 2 */
|
||||
#define CPCAP_REG_USBC3 0x0e08 /* USB Control 3 */
|
||||
#define CPCAP_REG_UVIDL 0x0e0c /* ULPI Vendor ID Low */
|
||||
#define CPCAP_REG_UVIDH 0x0e10 /* ULPI Vendor ID High */
|
||||
#define CPCAP_REG_UPIDL 0x0e14 /* ULPI Product ID Low */
|
||||
#define CPCAP_REG_UPIDH 0x0e18 /* ULPI Product ID High */
|
||||
#define CPCAP_REG_UFC1 0x0e1c /* ULPI Function Control 1 */
|
||||
#define CPCAP_REG_UFC2 0x0e20 /* ULPI Function Control 2 */
|
||||
#define CPCAP_REG_UFC3 0x0e24 /* ULPI Function Control 3 */
|
||||
#define CPCAP_REG_UIC1 0x0e28 /* ULPI Interface Control 1 */
|
||||
#define CPCAP_REG_UIC2 0x0e2c /* ULPI Interface Control 2 */
|
||||
#define CPCAP_REG_UIC3 0x0e30 /* ULPI Interface Control 3 */
|
||||
#define CPCAP_REG_USBOTG1 0x0e34 /* USB OTG Control 1 */
|
||||
#define CPCAP_REG_USBOTG2 0x0e38 /* USB OTG Control 2 */
|
||||
#define CPCAP_REG_USBOTG3 0x0e3c /* USB OTG Control 3 */
|
||||
#define CPCAP_REG_UIER1 0x0e40 /* USB Interrupt Enable Rising 1 */
|
||||
#define CPCAP_REG_UIER2 0x0e44 /* USB Interrupt Enable Rising 2 */
|
||||
#define CPCAP_REG_UIER3 0x0e48 /* USB Interrupt Enable Rising 3 */
|
||||
#define CPCAP_REG_UIEF1 0x0e4c /* USB Interrupt Enable Falling 1 */
|
||||
#define CPCAP_REG_UIEF2 0x0e50 /* USB Interrupt Enable Falling 1 */
|
||||
#define CPCAP_REG_UIEF3 0x0e54 /* USB Interrupt Enable Falling 1 */
|
||||
#define CPCAP_REG_UIS 0x0e58 /* USB Interrupt Status */
|
||||
#define CPCAP_REG_UIL 0x0e5c /* USB Interrupt Latch */
|
||||
#define CPCAP_REG_USBD 0x0e60 /* USB Debug */
|
||||
#define CPCAP_REG_SCR1 0x0e64 /* Scratch 1 */
|
||||
#define CPCAP_REG_SCR2 0x0e68 /* Scratch 2 */
|
||||
#define CPCAP_REG_SCR3 0x0e6c /* Scratch 3 */
|
||||
|
||||
#define CPCAP_REG_VMC 0x0eac /* Video Mux Control */
|
||||
#define CPCAP_REG_OWDC 0x0eb0 /* One Wire Device Control */
|
||||
#define CPCAP_REG_GPIO0 0x0eb4 /* GPIO 0 Control */
|
||||
|
||||
#define CPCAP_REG_GPIO1 0x0ebc /* GPIO 1 Control */
|
||||
|
||||
#define CPCAP_REG_GPIO2 0x0ec4 /* GPIO 2 Control */
|
||||
|
||||
#define CPCAP_REG_GPIO3 0x0ecc /* GPIO 3 Control */
|
||||
|
||||
#define CPCAP_REG_GPIO4 0x0ed4 /* GPIO 4 Control */
|
||||
|
||||
#define CPCAP_REG_GPIO5 0x0edc /* GPIO 5 Control */
|
||||
|
||||
#define CPCAP_REG_GPIO6 0x0ee4 /* GPIO 6 Control */
|
||||
|
||||
#define CPCAP_REG_MDLC 0x1000 /* Main Display Lighting Control */
|
||||
#define CPCAP_REG_KLC 0x1004 /* Keypad Lighting Control */
|
||||
#define CPCAP_REG_ADLC 0x1008 /* Aux Display Lighting Control */
|
||||
#define CPCAP_REG_REDC 0x100c /* Red Triode Control */
|
||||
#define CPCAP_REG_GREENC 0x1010 /* Green Triode Control */
|
||||
#define CPCAP_REG_BLUEC 0x1014 /* Blue Triode Control */
|
||||
#define CPCAP_REG_CFC 0x1018 /* Camera Flash Control */
|
||||
#define CPCAP_REG_ABC 0x101c /* Adaptive Boost Control */
|
||||
#define CPCAP_REG_BLEDC 0x1020 /* Bluetooth LED Control */
|
||||
#define CPCAP_REG_CLEDC 0x1024 /* Camera Privacy LED Control */
|
||||
|
||||
#define CPCAP_REG_OW1C 0x1200 /* One Wire 1 Command */
|
||||
#define CPCAP_REG_OW1D 0x1204 /* One Wire 1 Data */
|
||||
#define CPCAP_REG_OW1I 0x1208 /* One Wire 1 Interrupt */
|
||||
#define CPCAP_REG_OW1IE 0x120c /* One Wire 1 Interrupt Enable */
|
||||
|
||||
#define CPCAP_REG_OW1 0x1214 /* One Wire 1 Control */
|
||||
|
||||
#define CPCAP_REG_OW2C 0x1220 /* One Wire 2 Command */
|
||||
#define CPCAP_REG_OW2D 0x1224 /* One Wire 2 Data */
|
||||
#define CPCAP_REG_OW2I 0x1228 /* One Wire 2 Interrupt */
|
||||
#define CPCAP_REG_OW2IE 0x122c /* One Wire 2 Interrupt Enable */
|
||||
|
||||
#define CPCAP_REG_OW2 0x1234 /* One Wire 2 Control */
|
||||
|
||||
#define CPCAP_REG_OW3C 0x1240 /* One Wire 3 Command */
|
||||
#define CPCAP_REG_OW3D 0x1244 /* One Wire 3 Data */
|
||||
#define CPCAP_REG_OW3I 0x1248 /* One Wire 3 Interrupt */
|
||||
#define CPCAP_REG_OW3IE 0x124c /* One Wire 3 Interrupt Enable */
|
||||
|
||||
#define CPCAP_REG_OW3 0x1254 /* One Wire 3 Control */
|
||||
#define CPCAP_REG_GCAIC 0x1258 /* GCAI Clock Control */
|
||||
#define CPCAP_REG_GCAIM 0x125c /* GCAI GPIO Mode */
|
||||
#define CPCAP_REG_LGDIR 0x1260 /* LMR GCAI GPIO Direction */
|
||||
#define CPCAP_REG_LGPU 0x1264 /* LMR GCAI GPIO Pull-up */
|
||||
#define CPCAP_REG_LGPIN 0x1268 /* LMR GCAI GPIO Pin */
|
||||
#define CPCAP_REG_LGMASK 0x126c /* LMR GCAI GPIO Mask */
|
||||
#define CPCAP_REG_LDEB 0x1270 /* LMR Debounce Settings */
|
||||
#define CPCAP_REG_LGDET 0x1274 /* LMR GCAI Detach Detect */
|
||||
#define CPCAP_REG_LMISC 0x1278 /* LMR Misc Bits */
|
||||
#define CPCAP_REG_LMACE 0x127c /* LMR Mace IC Support */
|
||||
|
||||
#define CPCAP_REG_TEST 0x7c00 /* Test */
|
||||
|
||||
#define CPCAP_REG_ST_TEST1 0x7d08 /* ST Test1 */
|
||||
|
||||
#define CPCAP_REG_ST_TEST2 0x7d18 /* ST Test2 */
|
||||
|
||||
/*
|
||||
* Helpers for child devices to check the revision and vendor.
|
||||
*
|
||||
* REVISIT: No documentation for the bits below, please update
|
||||
* to use proper names for defines when available.
|
||||
*/
|
||||
|
||||
static inline int cpcap_get_revision(struct device *dev,
|
||||
struct regmap *regmap,
|
||||
u16 *revision)
|
||||
{
|
||||
unsigned int val;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(regmap, CPCAP_REG_VERSC1, &val);
|
||||
if (ret) {
|
||||
dev_err(dev, "Could not read revision\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
*revision = ((val >> 3) & 0x7) | ((val << 3) & 0x38);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int cpcap_get_vendor(struct device *dev,
|
||||
struct regmap *regmap,
|
||||
u16 *vendor)
|
||||
{
|
||||
unsigned int val;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(regmap, CPCAP_REG_VERSC1, &val);
|
||||
if (ret) {
|
||||
dev_err(dev, "Could not read vendor\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
*vendor = (val >> 6) & 0x7;
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue