Hi Linus,
Changes to the core: - Honour PLATFORM_DEVID_NONE and PLATFORM_DEVID_AUTO dev IDs Changes to existing drivers: - IRQ additions/fixes; axp20x, da9063-core - Code simplification; i2c-dln2 - Regmap additions/fixes; max77693 - Error checking/handling improvements; dln2, db8500-prcmu - Bug fixes; dln2, wm8350-core - DT support/documentation; max77693, max77686, tps65217, twl4030-power, gpio-tc3589x - Decouple syscon interface from platform devices - Use MFD hotplug registration; rtsx_usb, viperboard, hid-sensor-hub - Regulator fixups; sec-core - Power Management additions/fixes; rts5227, tc6393xb - Remove relic/redundant code; ab8500-sysctrl, lpc_sch, max77693-private - Clean-up/coding style changes; tps65090 - Clk additions/fixes; tc6393xb, tc6387xb, t7l66xb - Add USB-SPI support; dln2 - Trivial changes; max14577, arizona-spi, lpc_sch, wm8997-tables, wm5102-tables wm5110-tables, axp20x, atmel-hlcdc, rtsx_pci New drivers/supported devices: - axp288 PMIC support added to axp20x - s2mps13 support added to sec-core - New support for Diolan DLN-2 - New support for atmel-hlcdc -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJUhZDaAAoJEFGvii+H/HdhEY4P+gOlEIU+LYDdKmRjXLp85+ZS zrkLQdxvRp61LzzcIMGnduPFAOk8ixb3nRqSJv7P5WQG26I6qoI44zeTF2iSmLTp iVLtXRFSlo/lRyWT+2jXwL5iC47PCoJuJajNeM/YEbMERR3sWWAPrATZrQSPoKcZ D3qtXge3d+zq2rqpSvNAFNPEC4i9xawwa9GHMte9T/XhaoyVhaK6ITMsh0RK4B0p RRc2zy9BGEkuZMu3aC7P/qhfu3uSrxzI6FCHNSbZt/p5aq8klMBGqpK9Tgg4UHUG jqAd2lCXHVSVI07CO0YvVUDWV+5NlB1kAeRddohJujV9o5ciaqKCGPKK1Fz0PMxf u30t0X4Fb4QCAZVeo1hX9KWKQaQinUzPhANT4Sz0DY1S7arZ6PlJO/obGIys5JCf ElJuYNSRqRp6DcaoTHf19DUcxJXnqk73PU3hmsdS4UkweBWDYeagK2gqDwjIhAY6 DJZ5uqaa829fx/Jj8sUo0EgWZs/Cahf/td7y35fM4bMgU+vHd1xeBvMeltiJ2kuC OoZwtyHbV29sMCL2i5VQMkTkLJz49hPOEZolDKUxsV1QEPhi62DRmiHZlKABh3+D wzTkTRLfDhlrNedY529/1i3IxIlnzWXfInohe+WadapTFXuISIv6dyAyh9eNKnfd ZVf+1NwaCGbZbbPkSBqK =dJJd -----END PGP SIGNATURE----- Merge tag 'mfd-for-linus-3.19' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd Pull MFD updates from Lee Jones: "Changes to the core: - Honour PLATFORM_DEVID_NONE and PLATFORM_DEVID_AUTO dev IDs Changes to existing drivers: - IRQ additions/fixes; axp20x, da9063-core - Code simplification; i2c-dln2 - Regmap additions/fixes; max77693 - Error checking/handling improvements; dln2, db8500-prcmu - Bug fixes; dln2, wm8350-core - DT support/documentation; max77693, max77686, tps65217, twl4030-power, gpio-tc3589x - Decouple syscon interface from platform devices - Use MFD hotplug registration; rtsx_usb, viperboard, hid-sensor-hub - Regulator fixups; sec-core - Power Management additions/fixes; rts5227, tc6393xb - Remove relic/redundant code; ab8500-sysctrl, lpc_sch, max77693-private - Clean-up/coding style changes; tps65090 - Clk additions/fixes; tc6393xb, tc6387xb, t7l66xb - Add USB-SPI support; dln2 - Trivial changes; max14577, arizona-spi, lpc_sch, wm8997-tables, wm5102-tables wm5110-tables, axp20x, atmel-hlcdc, rtsx_pci New drivers/supported devices: - axp288 PMIC support added to axp20x - s2mps13 support added to sec-core - New support for Diolan DLN-2 - New support for atmel-hlcdc" * tag 'mfd-for-linus-3.19' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd: (55 commits) mfd: rtsx: Add func to split u32 into register mfd: atmel-hlcdc: Add Kconfig option description and name mfd: da9063: Get irq base dynamically before registering device mfd: max14577: Fix obvious typo in company name in copyright mfd: axp20x: Constify axp20x_acpi_match and rid unused warning mfd: t7l66xb: prepare/unprepare clocks mfd: tc6387xb: prepare/unprepare clocks mfd: dln2: add support for USB-SPI module mfd: wm5110: Add missing registers for AIF2 channels 3-6 mfd: tc3589x: get rid of static base mfd: arizona: Document HP_CTRL_1L and HP_CTRL_1R registers mfd: wm8997: Mark INTERRUPT_STATUS_2_MASK as readable mfd: tc6393xb: Prepare/unprepare clocks mfd: tps65090: Fix bonkers indenting strategy mfd: tc6393xb: Fail ohci suspend if full state restore is required mfd: lpc_sch: Don't call mfd_remove_devices() mfd: wm8350-core: Fix probable mask then right shift defect mfd: ab8500-sysctrl: Drop ab8500_restart mfd: db8500-prcmu: Provide sane error path values mfd: db8500-prcmu: Check return of devm_ioremap for error ...
This commit is contained in:
commit
3a7dbed7f2
51
Documentation/devicetree/bindings/mfd/atmel-hlcdc.txt
Normal file
51
Documentation/devicetree/bindings/mfd/atmel-hlcdc.txt
Normal file
@ -0,0 +1,51 @@
|
||||
Device-Tree bindings for Atmel's HLCDC (High LCD Controller) MFD driver
|
||||
|
||||
Required properties:
|
||||
- compatible: value should be one of the following:
|
||||
"atmel,sama5d3-hlcdc"
|
||||
- reg: base address and size of the HLCDC device registers.
|
||||
- clock-names: the name of the 3 clocks requested by the HLCDC device.
|
||||
Should contain "periph_clk", "sys_clk" and "slow_clk".
|
||||
- clocks: should contain the 3 clocks requested by the HLCDC device.
|
||||
- interrupts: should contain the description of the HLCDC interrupt line
|
||||
|
||||
The HLCDC IP exposes two subdevices:
|
||||
- a PWM chip: see ../pwm/atmel-hlcdc-pwm.txt
|
||||
- a Display Controller: see ../drm/atmel-hlcdc-dc.txt
|
||||
|
||||
Example:
|
||||
|
||||
hlcdc: hlcdc@f0030000 {
|
||||
compatible = "atmel,sama5d3-hlcdc";
|
||||
reg = <0xf0030000 0x2000>;
|
||||
clocks = <&lcdc_clk>, <&lcdck>, <&clk32k>;
|
||||
clock-names = "periph_clk","sys_clk", "slow_clk";
|
||||
interrupts = <36 IRQ_TYPE_LEVEL_HIGH 0>;
|
||||
status = "disabled";
|
||||
|
||||
hlcdc-display-controller {
|
||||
compatible = "atmel,hlcdc-display-controller";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_lcd_base &pinctrl_lcd_rgb888>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@0 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reg = <0>;
|
||||
|
||||
hlcdc_panel_output: endpoint@0 {
|
||||
reg = <0>;
|
||||
remote-endpoint = <&panel_input>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
hlcdc_pwm: hlcdc-pwm {
|
||||
compatible = "atmel,hlcdc-pwm";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_lcd_pwm>;
|
||||
#pwm-cells = <3>;
|
||||
};
|
||||
};
|
@ -34,6 +34,12 @@ to get matched with their hardware counterparts as follow:
|
||||
-BUCKn : for BUCKs, where n can lie in range 1 to 9.
|
||||
example: BUCK1, BUCK5, BUCK9.
|
||||
|
||||
Regulators which can be turned off during system suspend:
|
||||
-LDOn : 2, 6-8, 10-12, 14-16,
|
||||
-BUCKn : 1-4.
|
||||
Use standard regulator bindings for it ('regulator-off-in-suspend').
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
max77686@09 {
|
||||
|
@ -27,6 +27,20 @@ Optional properties:
|
||||
|
||||
[*] refer Documentation/devicetree/bindings/regulator/regulator.txt
|
||||
|
||||
- haptic : The MAX77693 haptic device utilises a PWM controlled motor to provide
|
||||
users with tactile feedback. PWM period and duty-cycle are varied in
|
||||
order to provide the approprite level of feedback.
|
||||
|
||||
Required properties:
|
||||
- compatible : Must be "maxim,max77693-hpatic"
|
||||
- haptic-supply : power supply for the haptic motor
|
||||
[*] refer Documentation/devicetree/bindings/regulator/regulator.txt
|
||||
- pwms : phandle to the physical PWM(Pulse Width Modulation) device.
|
||||
PWM properties should be named "pwms". And number of cell is different
|
||||
for each pwm device.
|
||||
To get more informations, please refer to documentaion.
|
||||
[*] refer Documentation/devicetree/bindings/pwm/pwm.txt
|
||||
|
||||
Example:
|
||||
max77693@66 {
|
||||
compatible = "maxim,max77693";
|
||||
@ -52,4 +66,11 @@ Example:
|
||||
regulator-boot-on;
|
||||
};
|
||||
};
|
||||
|
||||
haptic {
|
||||
compatible = "maxim,max77693-haptic";
|
||||
haptic-supply = <&haptic_supply>;
|
||||
pwms = <&pwm 0 40000 0>;
|
||||
pwm-names = "haptic";
|
||||
};
|
||||
};
|
||||
|
@ -1,5 +1,5 @@
|
||||
|
||||
* Samsung S2MPS11, S2MPS14 and S2MPU02 Voltage and Current Regulator
|
||||
* Samsung S2MPS11, S2MPS13, S2MPS14 and S2MPU02 Voltage and Current Regulator
|
||||
|
||||
The Samsung S2MPS11 is a multi-function device which includes voltage and
|
||||
current regulators, RTC, charger controller and other sub-blocks. It is
|
||||
@ -7,8 +7,8 @@ interfaced to the host controller using an I2C interface. Each sub-block is
|
||||
addressed by the host system using different I2C slave addresses.
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be "samsung,s2mps11-pmic" or "samsung,s2mps14-pmic"
|
||||
or "samsung,s2mpu02-pmic".
|
||||
- compatible: Should be "samsung,s2mps11-pmic" or "samsung,s2mps13-pmic"
|
||||
or "samsung,s2mps14-pmic" or "samsung,s2mpu02-pmic".
|
||||
- reg: Specifies the I2C slave address of the pmic block. It should be 0x66.
|
||||
|
||||
Optional properties:
|
||||
@ -17,8 +17,8 @@ Optional properties:
|
||||
- interrupts: Interrupt specifiers for interrupt sources.
|
||||
|
||||
Optional nodes:
|
||||
- clocks: s2mps11 and s5m8767 provide three(AP/CP/BT) buffered 32.768 KHz
|
||||
outputs, so to register these as clocks with common clock framework
|
||||
- clocks: s2mps11, s2mps13 and s5m8767 provide three(AP/CP/BT) buffered 32.768
|
||||
KHz outputs, so to register these as clocks with common clock framework
|
||||
instantiate a sub-node named "clocks". It uses the common clock binding
|
||||
documented in :
|
||||
[Documentation/devicetree/bindings/clock/clock-bindings.txt]
|
||||
@ -30,12 +30,12 @@ Optional nodes:
|
||||
the clock which they consume.
|
||||
Clock ID Devices
|
||||
----------------------------------------------------------
|
||||
32KhzAP 0 S2MPS11, S2MPS14, S5M8767
|
||||
32KhzCP 1 S2MPS11, S5M8767
|
||||
32KhzBT 2 S2MPS11, S2MPS14, S5M8767
|
||||
32KhzAP 0 S2MPS11, S2MPS13, S2MPS14, S5M8767
|
||||
32KhzCP 1 S2MPS11, S2MPS13, S5M8767
|
||||
32KhzBT 2 S2MPS11, S2MPS13, S2MPS14, S5M8767
|
||||
|
||||
- compatible: Should be one of: "samsung,s2mps11-clk", "samsung,s2mps14-clk",
|
||||
"samsung,s5m8767-clk"
|
||||
- compatible: Should be one of: "samsung,s2mps11-clk", "samsung,s2mps13-clk",
|
||||
"samsung,s2mps14-clk", "samsung,s5m8767-clk"
|
||||
|
||||
- regulators: The regulators of s2mps11 that have to be instantiated should be
|
||||
included in a sub-node named 'regulators'. Regulator nodes included in this
|
||||
@ -81,12 +81,14 @@ as per the datasheet of s2mps11.
|
||||
- LDOn
|
||||
- valid values for n are:
|
||||
- S2MPS11: 1 to 38
|
||||
- S2MPS13: 1 to 40
|
||||
- S2MPS14: 1 to 25
|
||||
- S2MPU02: 1 to 28
|
||||
- Example: LDO1, LDO2, LDO28
|
||||
- BUCKn
|
||||
- valid values for n are:
|
||||
- S2MPS11: 1 to 10
|
||||
- S2MPS13: 1 to 10
|
||||
- S2MPS14: 1 to 5
|
||||
- S2MPU02: 1 to 7
|
||||
- Example: BUCK1, BUCK2, BUCK9
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mfd/samsung/s2mps11.h>
|
||||
#include <linux/mfd/samsung/s2mps13.h>
|
||||
#include <linux/mfd/samsung/s2mps14.h>
|
||||
#include <linux/mfd/samsung/s5m8767.h>
|
||||
#include <linux/mfd/samsung/core.h>
|
||||
@ -120,6 +121,24 @@ static struct clk_init_data s2mps11_clks_init[S2MPS11_CLKS_NUM] = {
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_init_data s2mps13_clks_init[S2MPS11_CLKS_NUM] = {
|
||||
[S2MPS11_CLK_AP] = {
|
||||
.name = "s2mps13_ap",
|
||||
.ops = &s2mps11_clk_ops,
|
||||
.flags = CLK_IS_ROOT,
|
||||
},
|
||||
[S2MPS11_CLK_CP] = {
|
||||
.name = "s2mps13_cp",
|
||||
.ops = &s2mps11_clk_ops,
|
||||
.flags = CLK_IS_ROOT,
|
||||
},
|
||||
[S2MPS11_CLK_BT] = {
|
||||
.name = "s2mps13_bt",
|
||||
.ops = &s2mps11_clk_ops,
|
||||
.flags = CLK_IS_ROOT,
|
||||
},
|
||||
};
|
||||
|
||||
static struct clk_init_data s2mps14_clks_init[S2MPS11_CLKS_NUM] = {
|
||||
[S2MPS11_CLK_AP] = {
|
||||
.name = "s2mps14_ap",
|
||||
@ -184,6 +203,10 @@ static int s2mps11_clk_probe(struct platform_device *pdev)
|
||||
s2mps11_reg = S2MPS11_REG_RTC_CTRL;
|
||||
clks_init = s2mps11_clks_init;
|
||||
break;
|
||||
case S2MPS13X:
|
||||
s2mps11_reg = S2MPS13_REG_RTCCTRL;
|
||||
clks_init = s2mps13_clks_init;
|
||||
break;
|
||||
case S2MPS14X:
|
||||
s2mps11_reg = S2MPS14_REG_RTCCTRL;
|
||||
clks_init = s2mps14_clks_init;
|
||||
@ -279,6 +302,7 @@ static int s2mps11_clk_remove(struct platform_device *pdev)
|
||||
|
||||
static const struct platform_device_id s2mps11_clk_id[] = {
|
||||
{ "s2mps11-clk", S2MPS11X},
|
||||
{ "s2mps13-clk", S2MPS13X},
|
||||
{ "s2mps14-clk", S2MPS14X},
|
||||
{ "s5m8767-clk", S5M8767X},
|
||||
{ },
|
||||
|
@ -905,4 +905,16 @@ config GPIO_VIPERBOARD
|
||||
River Tech's viperboard.h for detailed meaning
|
||||
of the module parameters.
|
||||
|
||||
config GPIO_DLN2
|
||||
tristate "Diolan DLN2 GPIO support"
|
||||
depends on MFD_DLN2
|
||||
select GPIOLIB_IRQCHIP
|
||||
|
||||
help
|
||||
Select this option to enable GPIO driver for the Diolan DLN2
|
||||
board.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called gpio-dln2.
|
||||
|
||||
endif
|
||||
|
@ -26,6 +26,7 @@ obj-$(CONFIG_GPIO_CRYSTAL_COVE) += gpio-crystalcove.o
|
||||
obj-$(CONFIG_GPIO_DA9052) += gpio-da9052.o
|
||||
obj-$(CONFIG_GPIO_DA9055) += gpio-da9055.o
|
||||
obj-$(CONFIG_GPIO_DAVINCI) += gpio-davinci.o
|
||||
obj-$(CONFIG_GPIO_DLN2) += gpio-dln2.o
|
||||
obj-$(CONFIG_GPIO_DWAPB) += gpio-dwapb.o
|
||||
obj-$(CONFIG_GPIO_EM) += gpio-em.o
|
||||
obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o
|
||||
|
553
drivers/gpio/gpio-dln2.c
Normal file
553
drivers/gpio/gpio-dln2.c
Normal file
@ -0,0 +1,553 @@
|
||||
/*
|
||||
* Driver for the Diolan DLN-2 USB-GPIO adapter
|
||||
*
|
||||
* Copyright (c) 2014 Intel Corporation
|
||||
*
|
||||
* 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, version 2.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/irqchip/chained_irq.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mfd/dln2.h>
|
||||
|
||||
#define DLN2_GPIO_ID 0x01
|
||||
|
||||
#define DLN2_GPIO_GET_PIN_COUNT DLN2_CMD(0x01, DLN2_GPIO_ID)
|
||||
#define DLN2_GPIO_SET_DEBOUNCE DLN2_CMD(0x04, DLN2_GPIO_ID)
|
||||
#define DLN2_GPIO_GET_DEBOUNCE DLN2_CMD(0x05, DLN2_GPIO_ID)
|
||||
#define DLN2_GPIO_PORT_GET_VAL DLN2_CMD(0x06, DLN2_GPIO_ID)
|
||||
#define DLN2_GPIO_PIN_GET_VAL DLN2_CMD(0x0B, DLN2_GPIO_ID)
|
||||
#define DLN2_GPIO_PIN_SET_OUT_VAL DLN2_CMD(0x0C, DLN2_GPIO_ID)
|
||||
#define DLN2_GPIO_PIN_GET_OUT_VAL DLN2_CMD(0x0D, DLN2_GPIO_ID)
|
||||
#define DLN2_GPIO_CONDITION_MET_EV DLN2_CMD(0x0F, DLN2_GPIO_ID)
|
||||
#define DLN2_GPIO_PIN_ENABLE DLN2_CMD(0x10, DLN2_GPIO_ID)
|
||||
#define DLN2_GPIO_PIN_DISABLE DLN2_CMD(0x11, DLN2_GPIO_ID)
|
||||
#define DLN2_GPIO_PIN_SET_DIRECTION DLN2_CMD(0x13, DLN2_GPIO_ID)
|
||||
#define DLN2_GPIO_PIN_GET_DIRECTION DLN2_CMD(0x14, DLN2_GPIO_ID)
|
||||
#define DLN2_GPIO_PIN_SET_EVENT_CFG DLN2_CMD(0x1E, DLN2_GPIO_ID)
|
||||
#define DLN2_GPIO_PIN_GET_EVENT_CFG DLN2_CMD(0x1F, DLN2_GPIO_ID)
|
||||
|
||||
#define DLN2_GPIO_EVENT_NONE 0
|
||||
#define DLN2_GPIO_EVENT_CHANGE 1
|
||||
#define DLN2_GPIO_EVENT_LVL_HIGH 2
|
||||
#define DLN2_GPIO_EVENT_LVL_LOW 3
|
||||
#define DLN2_GPIO_EVENT_CHANGE_RISING 0x11
|
||||
#define DLN2_GPIO_EVENT_CHANGE_FALLING 0x21
|
||||
#define DLN2_GPIO_EVENT_MASK 0x0F
|
||||
|
||||
#define DLN2_GPIO_MAX_PINS 32
|
||||
|
||||
struct dln2_irq_work {
|
||||
struct work_struct work;
|
||||
struct dln2_gpio *dln2;
|
||||
int pin;
|
||||
int type;
|
||||
};
|
||||
|
||||
struct dln2_gpio {
|
||||
struct platform_device *pdev;
|
||||
struct gpio_chip gpio;
|
||||
|
||||
/*
|
||||
* Cache pin direction to save us one transfer, since the hardware has
|
||||
* separate commands to read the in and out values.
|
||||
*/
|
||||
DECLARE_BITMAP(output_enabled, DLN2_GPIO_MAX_PINS);
|
||||
|
||||
DECLARE_BITMAP(irqs_masked, DLN2_GPIO_MAX_PINS);
|
||||
DECLARE_BITMAP(irqs_enabled, DLN2_GPIO_MAX_PINS);
|
||||
DECLARE_BITMAP(irqs_pending, DLN2_GPIO_MAX_PINS);
|
||||
struct dln2_irq_work *irq_work;
|
||||
};
|
||||
|
||||
struct dln2_gpio_pin {
|
||||
__le16 pin;
|
||||
};
|
||||
|
||||
struct dln2_gpio_pin_val {
|
||||
__le16 pin __packed;
|
||||
u8 value;
|
||||
};
|
||||
|
||||
static int dln2_gpio_get_pin_count(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
__le16 count;
|
||||
int len = sizeof(count);
|
||||
|
||||
ret = dln2_transfer_rx(pdev, DLN2_GPIO_GET_PIN_COUNT, &count, &len);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (len < sizeof(count))
|
||||
return -EPROTO;
|
||||
|
||||
return le16_to_cpu(count);
|
||||
}
|
||||
|
||||
static int dln2_gpio_pin_cmd(struct dln2_gpio *dln2, int cmd, unsigned pin)
|
||||
{
|
||||
struct dln2_gpio_pin req = {
|
||||
.pin = cpu_to_le16(pin),
|
||||
};
|
||||
|
||||
return dln2_transfer_tx(dln2->pdev, cmd, &req, sizeof(req));
|
||||
}
|
||||
|
||||
static int dln2_gpio_pin_val(struct dln2_gpio *dln2, int cmd, unsigned int pin)
|
||||
{
|
||||
int ret;
|
||||
struct dln2_gpio_pin req = {
|
||||
.pin = cpu_to_le16(pin),
|
||||
};
|
||||
struct dln2_gpio_pin_val rsp;
|
||||
int len = sizeof(rsp);
|
||||
|
||||
ret = dln2_transfer(dln2->pdev, cmd, &req, sizeof(req), &rsp, &len);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (len < sizeof(rsp) || req.pin != rsp.pin)
|
||||
return -EPROTO;
|
||||
|
||||
return rsp.value;
|
||||
}
|
||||
|
||||
static int dln2_gpio_pin_get_in_val(struct dln2_gpio *dln2, unsigned int pin)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = dln2_gpio_pin_val(dln2, DLN2_GPIO_PIN_GET_VAL, pin);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return !!ret;
|
||||
}
|
||||
|
||||
static int dln2_gpio_pin_get_out_val(struct dln2_gpio *dln2, unsigned int pin)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = dln2_gpio_pin_val(dln2, DLN2_GPIO_PIN_GET_OUT_VAL, pin);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return !!ret;
|
||||
}
|
||||
|
||||
static void dln2_gpio_pin_set_out_val(struct dln2_gpio *dln2,
|
||||
unsigned int pin, int value)
|
||||
{
|
||||
struct dln2_gpio_pin_val req = {
|
||||
.pin = cpu_to_le16(pin),
|
||||
.value = value,
|
||||
};
|
||||
|
||||
dln2_transfer_tx(dln2->pdev, DLN2_GPIO_PIN_SET_OUT_VAL, &req,
|
||||
sizeof(req));
|
||||
}
|
||||
|
||||
#define DLN2_GPIO_DIRECTION_IN 0
|
||||
#define DLN2_GPIO_DIRECTION_OUT 1
|
||||
|
||||
static int dln2_gpio_request(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
struct dln2_gpio *dln2 = container_of(chip, struct dln2_gpio, gpio);
|
||||
struct dln2_gpio_pin req = {
|
||||
.pin = cpu_to_le16(offset),
|
||||
};
|
||||
struct dln2_gpio_pin_val rsp;
|
||||
int len = sizeof(rsp);
|
||||
int ret;
|
||||
|
||||
ret = dln2_gpio_pin_cmd(dln2, DLN2_GPIO_PIN_ENABLE, offset);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* cache the pin direction */
|
||||
ret = dln2_transfer(dln2->pdev, DLN2_GPIO_PIN_GET_DIRECTION,
|
||||
&req, sizeof(req), &rsp, &len);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (len < sizeof(rsp) || req.pin != rsp.pin) {
|
||||
ret = -EPROTO;
|
||||
goto out_disable;
|
||||
}
|
||||
|
||||
switch (rsp.value) {
|
||||
case DLN2_GPIO_DIRECTION_IN:
|
||||
clear_bit(offset, dln2->output_enabled);
|
||||
return 0;
|
||||
case DLN2_GPIO_DIRECTION_OUT:
|
||||
set_bit(offset, dln2->output_enabled);
|
||||
return 0;
|
||||
default:
|
||||
ret = -EPROTO;
|
||||
goto out_disable;
|
||||
}
|
||||
|
||||
out_disable:
|
||||
dln2_gpio_pin_cmd(dln2, DLN2_GPIO_PIN_DISABLE, offset);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void dln2_gpio_free(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
struct dln2_gpio *dln2 = container_of(chip, struct dln2_gpio, gpio);
|
||||
|
||||
dln2_gpio_pin_cmd(dln2, DLN2_GPIO_PIN_DISABLE, offset);
|
||||
}
|
||||
|
||||
static int dln2_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
struct dln2_gpio *dln2 = container_of(chip, struct dln2_gpio, gpio);
|
||||
|
||||
if (test_bit(offset, dln2->output_enabled))
|
||||
return GPIOF_DIR_OUT;
|
||||
|
||||
return GPIOF_DIR_IN;
|
||||
}
|
||||
|
||||
static int dln2_gpio_get(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
struct dln2_gpio *dln2 = container_of(chip, struct dln2_gpio, gpio);
|
||||
int dir;
|
||||
|
||||
dir = dln2_gpio_get_direction(chip, offset);
|
||||
if (dir < 0)
|
||||
return dir;
|
||||
|
||||
if (dir == GPIOF_DIR_IN)
|
||||
return dln2_gpio_pin_get_in_val(dln2, offset);
|
||||
|
||||
return dln2_gpio_pin_get_out_val(dln2, offset);
|
||||
}
|
||||
|
||||
static void dln2_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
|
||||
{
|
||||
struct dln2_gpio *dln2 = container_of(chip, struct dln2_gpio, gpio);
|
||||
|
||||
dln2_gpio_pin_set_out_val(dln2, offset, value);
|
||||
}
|
||||
|
||||
static int dln2_gpio_set_direction(struct gpio_chip *chip, unsigned offset,
|
||||
unsigned dir)
|
||||
{
|
||||
struct dln2_gpio *dln2 = container_of(chip, struct dln2_gpio, gpio);
|
||||
struct dln2_gpio_pin_val req = {
|
||||
.pin = cpu_to_le16(offset),
|
||||
.value = dir,
|
||||
};
|
||||
int ret;
|
||||
|
||||
ret = dln2_transfer_tx(dln2->pdev, DLN2_GPIO_PIN_SET_DIRECTION,
|
||||
&req, sizeof(req));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (dir == DLN2_GPIO_DIRECTION_OUT)
|
||||
set_bit(offset, dln2->output_enabled);
|
||||
else
|
||||
clear_bit(offset, dln2->output_enabled);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dln2_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
return dln2_gpio_set_direction(chip, offset, DLN2_GPIO_DIRECTION_IN);
|
||||
}
|
||||
|
||||
static int dln2_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
|
||||
int value)
|
||||
{
|
||||
return dln2_gpio_set_direction(chip, offset, DLN2_GPIO_DIRECTION_OUT);
|
||||
}
|
||||
|
||||
static int dln2_gpio_set_debounce(struct gpio_chip *chip, unsigned offset,
|
||||
unsigned debounce)
|
||||
{
|
||||
struct dln2_gpio *dln2 = container_of(chip, struct dln2_gpio, gpio);
|
||||
__le32 duration = cpu_to_le32(debounce);
|
||||
|
||||
return dln2_transfer_tx(dln2->pdev, DLN2_GPIO_SET_DEBOUNCE,
|
||||
&duration, sizeof(duration));
|
||||
}
|
||||
|
||||
static int dln2_gpio_set_event_cfg(struct dln2_gpio *dln2, unsigned pin,
|
||||
unsigned type, unsigned period)
|
||||
{
|
||||
struct {
|
||||
__le16 pin;
|
||||
u8 type;
|
||||
__le16 period;
|
||||
} __packed req = {
|
||||
.pin = cpu_to_le16(pin),
|
||||
.type = type,
|
||||
.period = cpu_to_le16(period),
|
||||
};
|
||||
|
||||
return dln2_transfer_tx(dln2->pdev, DLN2_GPIO_PIN_SET_EVENT_CFG,
|
||||
&req, sizeof(req));
|
||||
}
|
||||
|
||||
static void dln2_irq_work(struct work_struct *w)
|
||||
{
|
||||
struct dln2_irq_work *iw = container_of(w, struct dln2_irq_work, work);
|
||||
struct dln2_gpio *dln2 = iw->dln2;
|
||||
u8 type = iw->type & DLN2_GPIO_EVENT_MASK;
|
||||
|
||||
if (test_bit(iw->pin, dln2->irqs_enabled))
|
||||
dln2_gpio_set_event_cfg(dln2, iw->pin, type, 0);
|
||||
else
|
||||
dln2_gpio_set_event_cfg(dln2, iw->pin, DLN2_GPIO_EVENT_NONE, 0);
|
||||
}
|
||||
|
||||
static void dln2_irq_enable(struct irq_data *irqd)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
|
||||
struct dln2_gpio *dln2 = container_of(gc, struct dln2_gpio, gpio);
|
||||
int pin = irqd_to_hwirq(irqd);
|
||||
|
||||
set_bit(pin, dln2->irqs_enabled);
|
||||
schedule_work(&dln2->irq_work[pin].work);
|
||||
}
|
||||
|
||||
static void dln2_irq_disable(struct irq_data *irqd)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
|
||||
struct dln2_gpio *dln2 = container_of(gc, struct dln2_gpio, gpio);
|
||||
int pin = irqd_to_hwirq(irqd);
|
||||
|
||||
clear_bit(pin, dln2->irqs_enabled);
|
||||
schedule_work(&dln2->irq_work[pin].work);
|
||||
}
|
||||
|
||||
static void dln2_irq_mask(struct irq_data *irqd)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
|
||||
struct dln2_gpio *dln2 = container_of(gc, struct dln2_gpio, gpio);
|
||||
int pin = irqd_to_hwirq(irqd);
|
||||
|
||||
set_bit(pin, dln2->irqs_masked);
|
||||
}
|
||||
|
||||
static void dln2_irq_unmask(struct irq_data *irqd)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
|
||||
struct dln2_gpio *dln2 = container_of(gc, struct dln2_gpio, gpio);
|
||||
struct device *dev = dln2->gpio.dev;
|
||||
int pin = irqd_to_hwirq(irqd);
|
||||
|
||||
if (test_and_clear_bit(pin, dln2->irqs_pending)) {
|
||||
int irq;
|
||||
|
||||
irq = irq_find_mapping(dln2->gpio.irqdomain, pin);
|
||||
if (!irq) {
|
||||
dev_err(dev, "pin %d not mapped to IRQ\n", pin);
|
||||
return;
|
||||
}
|
||||
|
||||
generic_handle_irq(irq);
|
||||
}
|
||||
}
|
||||
|
||||
static int dln2_irq_set_type(struct irq_data *irqd, unsigned type)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
|
||||
struct dln2_gpio *dln2 = container_of(gc, struct dln2_gpio, gpio);
|
||||
int pin = irqd_to_hwirq(irqd);
|
||||
|
||||
switch (type) {
|
||||
case IRQ_TYPE_LEVEL_HIGH:
|
||||
dln2->irq_work[pin].type = DLN2_GPIO_EVENT_LVL_HIGH;
|
||||
break;
|
||||
case IRQ_TYPE_LEVEL_LOW:
|
||||
dln2->irq_work[pin].type = DLN2_GPIO_EVENT_LVL_LOW;
|
||||
break;
|
||||
case IRQ_TYPE_EDGE_BOTH:
|
||||
dln2->irq_work[pin].type = DLN2_GPIO_EVENT_CHANGE;
|
||||
break;
|
||||
case IRQ_TYPE_EDGE_RISING:
|
||||
dln2->irq_work[pin].type = DLN2_GPIO_EVENT_CHANGE_RISING;
|
||||
break;
|
||||
case IRQ_TYPE_EDGE_FALLING:
|
||||
dln2->irq_work[pin].type = DLN2_GPIO_EVENT_CHANGE_FALLING;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct irq_chip dln2_gpio_irqchip = {
|
||||
.name = "dln2-irq",
|
||||
.irq_enable = dln2_irq_enable,
|
||||
.irq_disable = dln2_irq_disable,
|
||||
.irq_mask = dln2_irq_mask,
|
||||
.irq_unmask = dln2_irq_unmask,
|
||||
.irq_set_type = dln2_irq_set_type,
|
||||
};
|
||||
|
||||
static void dln2_gpio_event(struct platform_device *pdev, u16 echo,
|
||||
const void *data, int len)
|
||||
{
|
||||
int pin, irq;
|
||||
const struct {
|
||||
__le16 count;
|
||||
__u8 type;
|
||||
__le16 pin;
|
||||
__u8 value;
|
||||
} __packed *event = data;
|
||||
struct dln2_gpio *dln2 = platform_get_drvdata(pdev);
|
||||
|
||||
if (len < sizeof(*event)) {
|
||||
dev_err(dln2->gpio.dev, "short event message\n");
|
||||
return;
|
||||
}
|
||||
|
||||
pin = le16_to_cpu(event->pin);
|
||||
if (pin >= dln2->gpio.ngpio) {
|
||||
dev_err(dln2->gpio.dev, "out of bounds pin %d\n", pin);
|
||||
return;
|
||||
}
|
||||
|
||||
irq = irq_find_mapping(dln2->gpio.irqdomain, pin);
|
||||
if (!irq) {
|
||||
dev_err(dln2->gpio.dev, "pin %d not mapped to IRQ\n", pin);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!test_bit(pin, dln2->irqs_enabled))
|
||||
return;
|
||||
if (test_bit(pin, dln2->irqs_masked)) {
|
||||
set_bit(pin, dln2->irqs_pending);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (dln2->irq_work[pin].type) {
|
||||
case DLN2_GPIO_EVENT_CHANGE_RISING:
|
||||
if (event->value)
|
||||
generic_handle_irq(irq);
|
||||
break;
|
||||
case DLN2_GPIO_EVENT_CHANGE_FALLING:
|
||||
if (!event->value)
|
||||
generic_handle_irq(irq);
|
||||
break;
|
||||
default:
|
||||
generic_handle_irq(irq);
|
||||
}
|
||||
}
|
||||
|
||||
static int dln2_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct dln2_gpio *dln2;
|
||||
struct device *dev = &pdev->dev;
|
||||
int pins;
|
||||
int i, ret;
|
||||
|
||||
pins = dln2_gpio_get_pin_count(pdev);
|
||||
if (pins < 0) {
|
||||
dev_err(dev, "failed to get pin count: %d\n", pins);
|
||||
return pins;
|
||||
}
|
||||
if (pins > DLN2_GPIO_MAX_PINS) {
|
||||
pins = DLN2_GPIO_MAX_PINS;
|
||||
dev_warn(dev, "clamping pins to %d\n", DLN2_GPIO_MAX_PINS);
|
||||
}
|
||||
|
||||
dln2 = devm_kzalloc(&pdev->dev, sizeof(*dln2), GFP_KERNEL);
|
||||
if (!dln2)
|
||||
return -ENOMEM;
|
||||
|
||||
dln2->irq_work = devm_kcalloc(&pdev->dev, pins,
|
||||
sizeof(struct dln2_irq_work), GFP_KERNEL);
|
||||
if (!dln2->irq_work)
|
||||
return -ENOMEM;
|
||||
for (i = 0; i < pins; i++) {
|
||||
INIT_WORK(&dln2->irq_work[i].work, dln2_irq_work);
|
||||
dln2->irq_work[i].pin = i;
|
||||
dln2->irq_work[i].dln2 = dln2;
|
||||
}
|
||||
|
||||
dln2->pdev = pdev;
|
||||
|
||||
dln2->gpio.label = "dln2";
|
||||
dln2->gpio.dev = dev;
|
||||
dln2->gpio.owner = THIS_MODULE;
|
||||
dln2->gpio.base = -1;
|
||||
dln2->gpio.ngpio = pins;
|
||||
dln2->gpio.exported = true;
|
||||
dln2->gpio.can_sleep = true;
|
||||
dln2->gpio.irq_not_threaded = true;
|
||||
dln2->gpio.set = dln2_gpio_set;
|
||||
dln2->gpio.get = dln2_gpio_get;
|
||||
dln2->gpio.request = dln2_gpio_request;
|
||||
dln2->gpio.free = dln2_gpio_free;
|
||||
dln2->gpio.get_direction = dln2_gpio_get_direction;
|
||||
dln2->gpio.direction_input = dln2_gpio_direction_input;
|
||||
dln2->gpio.direction_output = dln2_gpio_direction_output;
|
||||
dln2->gpio.set_debounce = dln2_gpio_set_debounce;
|
||||
|
||||
platform_set_drvdata(pdev, dln2);
|
||||
|
||||
ret = gpiochip_add(&dln2->gpio);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to add gpio chip: %d\n", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = gpiochip_irqchip_add(&dln2->gpio, &dln2_gpio_irqchip, 0,
|
||||
handle_simple_irq, IRQ_TYPE_NONE);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to add irq chip: %d\n", ret);
|
||||
goto out_gpiochip_remove;
|
||||
}
|
||||
|
||||
ret = dln2_register_event_cb(pdev, DLN2_GPIO_CONDITION_MET_EV,
|
||||
dln2_gpio_event);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to register event cb: %d\n", ret);
|
||||
goto out_gpiochip_remove;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
out_gpiochip_remove:
|
||||
gpiochip_remove(&dln2->gpio);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dln2_gpio_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct dln2_gpio *dln2 = platform_get_drvdata(pdev);
|
||||
int i;
|
||||
|
||||
dln2_unregister_event_cb(pdev, DLN2_GPIO_CONDITION_MET_EV);
|
||||
for (i = 0; i < dln2->gpio.ngpio; i++)
|
||||
flush_work(&dln2->irq_work[i].work);
|
||||
gpiochip_remove(&dln2->gpio);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver dln2_gpio_driver = {
|
||||
.driver.name = "dln2-gpio",
|
||||
.probe = dln2_gpio_probe,
|
||||
.remove = dln2_gpio_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(dln2_gpio_driver);
|
||||
|
||||
MODULE_AUTHOR("Daniel Baluta <daniel.baluta@intel.com");
|
||||
MODULE_DESCRIPTION("Driver for the Diolan DLN2 GPIO interface");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_ALIAS("platform:dln2-gpio");
|
@ -262,7 +262,7 @@ static int tc3589x_gpio_probe(struct platform_device *pdev)
|
||||
tc3589x_gpio->chip = template_chip;
|
||||
tc3589x_gpio->chip.ngpio = tc3589x->num_gpio;
|
||||
tc3589x_gpio->chip.dev = &pdev->dev;
|
||||
tc3589x_gpio->chip.base = (pdata) ? pdata->gpio_base : -1;
|
||||
tc3589x_gpio->chip.base = -1;
|
||||
|
||||
#ifdef CONFIG_OF_GPIO
|
||||
tc3589x_gpio->chip.of_node = np;
|
||||
|
@ -640,9 +640,6 @@ static int sensor_hub_probe(struct hid_device *hdev,
|
||||
ret = -ENOMEM;
|
||||
goto err_stop_hw;
|
||||
}
|
||||
sd->hid_sensor_hub_client_devs[
|
||||
sd->hid_sensor_client_cnt].id =
|
||||
PLATFORM_DEVID_AUTO;
|
||||
sd->hid_sensor_hub_client_devs[
|
||||
sd->hid_sensor_client_cnt].name = name;
|
||||
sd->hid_sensor_hub_client_devs[
|
||||
@ -659,8 +656,9 @@ static int sensor_hub_probe(struct hid_device *hdev,
|
||||
if (last_hsdev)
|
||||
last_hsdev->end_collection_index = i;
|
||||
|
||||
ret = mfd_add_devices(&hdev->dev, 0, sd->hid_sensor_hub_client_devs,
|
||||
sd->hid_sensor_client_cnt, NULL, 0, NULL);
|
||||
ret = mfd_add_hotplug_devices(&hdev->dev,
|
||||
sd->hid_sensor_hub_client_devs,
|
||||
sd->hid_sensor_client_cnt);
|
||||
if (ret < 0)
|
||||
goto err_stop_hw;
|
||||
|
||||
|
@ -881,6 +881,16 @@ config I2C_DIOLAN_U2C
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-diolan-u2c.
|
||||
|
||||
config I2C_DLN2
|
||||
tristate "Diolan DLN-2 USB I2C adapter"
|
||||
depends on MFD_DLN2
|
||||
help
|
||||
If you say yes to this option, support will be included for Diolan
|
||||
DLN2, a USB to I2C interface.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-dln2.
|
||||
|
||||
config I2C_PARPORT
|
||||
tristate "Parallel port adapter"
|
||||
depends on PARPORT
|
||||
|
@ -87,6 +87,7 @@ obj-$(CONFIG_I2C_RCAR) += i2c-rcar.o
|
||||
|
||||
# External I2C/SMBus adapter drivers
|
||||
obj-$(CONFIG_I2C_DIOLAN_U2C) += i2c-diolan-u2c.o
|
||||
obj-$(CONFIG_I2C_DLN2) += i2c-dln2.o
|
||||
obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o
|
||||
obj-$(CONFIG_I2C_PARPORT_LIGHT) += i2c-parport-light.o
|
||||
obj-$(CONFIG_I2C_ROBOTFUZZ_OSIF) += i2c-robotfuzz-osif.o
|
||||
|
262
drivers/i2c/busses/i2c-dln2.c
Normal file
262
drivers/i2c/busses/i2c-dln2.c
Normal file
@ -0,0 +1,262 @@
|
||||
/*
|
||||
* Driver for the Diolan DLN-2 USB-I2C adapter
|
||||
*
|
||||
* Copyright (c) 2014 Intel Corporation
|
||||
*
|
||||
* Derived from:
|
||||
* i2c-diolan-u2c.c
|
||||
* Copyright (c) 2010-2011 Ericsson AB
|
||||
*
|
||||
* 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, version 2.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mfd/dln2.h>
|
||||
|
||||
#define DLN2_I2C_MODULE_ID 0x03
|
||||
#define DLN2_I2C_CMD(cmd) DLN2_CMD(cmd, DLN2_I2C_MODULE_ID)
|
||||
|
||||
/* I2C commands */
|
||||
#define DLN2_I2C_GET_PORT_COUNT DLN2_I2C_CMD(0x00)
|
||||
#define DLN2_I2C_ENABLE DLN2_I2C_CMD(0x01)
|
||||
#define DLN2_I2C_DISABLE DLN2_I2C_CMD(0x02)
|
||||
#define DLN2_I2C_IS_ENABLED DLN2_I2C_CMD(0x03)
|
||||
#define DLN2_I2C_WRITE DLN2_I2C_CMD(0x06)
|
||||
#define DLN2_I2C_READ DLN2_I2C_CMD(0x07)
|
||||
#define DLN2_I2C_SCAN_DEVICES DLN2_I2C_CMD(0x08)
|
||||
#define DLN2_I2C_PULLUP_ENABLE DLN2_I2C_CMD(0x09)
|
||||
#define DLN2_I2C_PULLUP_DISABLE DLN2_I2C_CMD(0x0A)
|
||||
#define DLN2_I2C_PULLUP_IS_ENABLED DLN2_I2C_CMD(0x0B)
|
||||
#define DLN2_I2C_TRANSFER DLN2_I2C_CMD(0x0C)
|
||||
#define DLN2_I2C_SET_MAX_REPLY_COUNT DLN2_I2C_CMD(0x0D)
|
||||
#define DLN2_I2C_GET_MAX_REPLY_COUNT DLN2_I2C_CMD(0x0E)
|
||||
|
||||
#define DLN2_I2C_MAX_XFER_SIZE 256
|
||||
#define DLN2_I2C_BUF_SIZE (DLN2_I2C_MAX_XFER_SIZE + 16)
|
||||
|
||||
struct dln2_i2c {
|
||||
struct platform_device *pdev;
|
||||
struct i2c_adapter adapter;
|
||||
u8 port;
|
||||
/*
|
||||
* Buffer to hold the packet for read or write transfers. One is enough
|
||||
* since we can't have multiple transfers in parallel on the i2c bus.
|
||||
*/
|
||||
void *buf;
|
||||
};
|
||||
|
||||
static int dln2_i2c_enable(struct dln2_i2c *dln2, bool enable)
|
||||
{
|
||||
u16 cmd;
|
||||
struct {
|
||||
u8 port;
|
||||
} tx;
|
||||
|
||||
tx.port = dln2->port;
|
||||
|
||||
if (enable)
|
||||
cmd = DLN2_I2C_ENABLE;
|
||||
else
|
||||
cmd = DLN2_I2C_DISABLE;
|
||||
|
||||
return dln2_transfer_tx(dln2->pdev, cmd, &tx, sizeof(tx));
|
||||
}
|
||||
|
||||
static int dln2_i2c_write(struct dln2_i2c *dln2, u8 addr,
|
||||
u8 *data, u16 data_len)
|
||||
{
|
||||
int ret;
|
||||
struct {
|
||||
u8 port;
|
||||
u8 addr;
|
||||
u8 mem_addr_len;
|
||||
__le32 mem_addr;
|
||||
__le16 buf_len;
|
||||
u8 buf[DLN2_I2C_MAX_XFER_SIZE];
|
||||
} __packed *tx = dln2->buf;
|
||||
unsigned len;
|
||||
|
||||
BUILD_BUG_ON(sizeof(*tx) > DLN2_I2C_BUF_SIZE);
|
||||
|
||||
tx->port = dln2->port;
|
||||
tx->addr = addr;
|
||||
tx->mem_addr_len = 0;
|
||||
tx->mem_addr = 0;
|
||||
tx->buf_len = cpu_to_le16(data_len);
|
||||
memcpy(tx->buf, data, data_len);
|
||||
|
||||
len = sizeof(*tx) + data_len - DLN2_I2C_MAX_XFER_SIZE;
|
||||
ret = dln2_transfer_tx(dln2->pdev, DLN2_I2C_WRITE, tx, len);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return data_len;
|
||||
}
|
||||
|
||||
static int dln2_i2c_read(struct dln2_i2c *dln2, u16 addr, u8 *data,
|
||||
u16 data_len)
|
||||
{
|
||||
int ret;
|
||||
struct {
|
||||
u8 port;
|
||||
u8 addr;
|
||||
u8 mem_addr_len;
|
||||
__le32 mem_addr;
|
||||
__le16 buf_len;
|
||||
} __packed tx;
|
||||
struct {
|
||||
__le16 buf_len;
|
||||
u8 buf[DLN2_I2C_MAX_XFER_SIZE];
|
||||
} __packed *rx = dln2->buf;
|
||||
unsigned rx_len = sizeof(*rx);
|
||||
|
||||
BUILD_BUG_ON(sizeof(*rx) > DLN2_I2C_BUF_SIZE);
|
||||
|
||||
tx.port = dln2->port;
|
||||
tx.addr = addr;
|
||||
tx.mem_addr_len = 0;
|
||||
tx.mem_addr = 0;
|
||||
tx.buf_len = cpu_to_le16(data_len);
|
||||
|
||||
ret = dln2_transfer(dln2->pdev, DLN2_I2C_READ, &tx, sizeof(tx),
|
||||
rx, &rx_len);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (rx_len < sizeof(rx->buf_len) + data_len)
|
||||
return -EPROTO;
|
||||
if (le16_to_cpu(rx->buf_len) != data_len)
|
||||
return -EPROTO;
|
||||
|
||||
memcpy(data, rx->buf, data_len);
|
||||
|
||||
return data_len;
|
||||
}
|
||||
|
||||
static int dln2_i2c_xfer(struct i2c_adapter *adapter,
|
||||
struct i2c_msg *msgs, int num)
|
||||
{
|
||||
struct dln2_i2c *dln2 = i2c_get_adapdata(adapter);
|
||||
struct i2c_msg *pmsg;
|
||||
struct device *dev = &dln2->adapter.dev;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
int ret;
|
||||
|
||||
pmsg = &msgs[i];
|
||||
|
||||
if (pmsg->len > DLN2_I2C_MAX_XFER_SIZE) {
|
||||
dev_warn(dev, "maximum transfer size exceeded\n");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (pmsg->flags & I2C_M_RD) {
|
||||
ret = dln2_i2c_read(dln2, pmsg->addr, pmsg->buf,
|
||||
pmsg->len);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
pmsg->len = ret;
|
||||
} else {
|
||||
ret = dln2_i2c_write(dln2, pmsg->addr, pmsg->buf,
|
||||
pmsg->len);
|
||||
if (ret != pmsg->len)
|
||||
return -EPROTO;
|
||||
}
|
||||
}
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
static u32 dln2_i2c_func(struct i2c_adapter *a)
|
||||
{
|
||||
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA |
|
||||
I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BLOCK_PROC_CALL |
|
||||
I2C_FUNC_SMBUS_I2C_BLOCK;
|
||||
}
|
||||
|
||||
static const struct i2c_algorithm dln2_i2c_usb_algorithm = {
|
||||
.master_xfer = dln2_i2c_xfer,
|
||||
.functionality = dln2_i2c_func,
|
||||
};
|
||||
|
||||
static int dln2_i2c_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
struct dln2_i2c *dln2;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct dln2_platform_data *pdata = dev_get_platdata(&pdev->dev);
|
||||
|
||||
dln2 = devm_kzalloc(dev, sizeof(*dln2), GFP_KERNEL);
|
||||
if (!dln2)
|
||||
return -ENOMEM;
|
||||
|
||||
dln2->buf = devm_kmalloc(dev, DLN2_I2C_BUF_SIZE, GFP_KERNEL);
|
||||
if (!dln2->buf)
|
||||
return -ENOMEM;
|
||||
|
||||
dln2->pdev = pdev;
|
||||
dln2->port = pdata->port;
|
||||
|
||||
/* setup i2c adapter description */
|
||||
dln2->adapter.owner = THIS_MODULE;
|
||||
dln2->adapter.class = I2C_CLASS_HWMON;
|
||||
dln2->adapter.algo = &dln2_i2c_usb_algorithm;
|
||||
dln2->adapter.dev.parent = dev;
|
||||
i2c_set_adapdata(&dln2->adapter, dln2);
|
||||
snprintf(dln2->adapter.name, sizeof(dln2->adapter.name), "%s-%s-%d",
|
||||
"dln2-i2c", dev_name(pdev->dev.parent), dln2->port);
|
||||
|
||||
platform_set_drvdata(pdev, dln2);
|
||||
|
||||
/* initialize the i2c interface */
|
||||
ret = dln2_i2c_enable(dln2, true);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to initialize adapter: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* and finally attach to i2c layer */
|
||||
ret = i2c_add_adapter(&dln2->adapter);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to add I2C adapter: %d\n", ret);
|
||||
goto out_disable;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
out_disable:
|
||||
dln2_i2c_enable(dln2, false);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dln2_i2c_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct dln2_i2c *dln2 = platform_get_drvdata(pdev);
|
||||
|
||||
i2c_del_adapter(&dln2->adapter);
|
||||
dln2_i2c_enable(dln2, false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver dln2_i2c_driver = {
|
||||
.driver.name = "dln2-i2c",
|
||||
.probe = dln2_i2c_probe,
|
||||
.remove = dln2_i2c_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(dln2_i2c_driver);
|
||||
|
||||
MODULE_AUTHOR("Laurentiu Palcu <laurentiu.palcu@intel.com>");
|
||||
MODULE_DESCRIPTION("Driver for the Diolan DLN2 I2C master interface");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_ALIAS("platform:dln2-i2c");
|
@ -127,6 +127,14 @@ config AT91_ADC
|
||||
help
|
||||
Say yes here to build support for Atmel AT91 ADC.
|
||||
|
||||
config AXP288_ADC
|
||||
tristate "X-Powers AXP288 ADC driver"
|
||||
depends on MFD_AXP20X
|
||||
help
|
||||
Say yes here to have support for X-Powers power management IC (PMIC) ADC
|
||||
device. Depending on platform configuration, this general purpose ADC can
|
||||
be used for sampling sensors such as thermal resistors.
|
||||
|
||||
config EXYNOS_ADC
|
||||
tristate "Exynos ADC driver support"
|
||||
depends on ARCH_EXYNOS || ARCH_S3C24XX || ARCH_S3C64XX || (OF && COMPILE_TEST)
|
||||
|
@ -14,6 +14,7 @@ obj-$(CONFIG_AD7793) += ad7793.o
|
||||
obj-$(CONFIG_AD7887) += ad7887.o
|
||||
obj-$(CONFIG_AD799X) += ad799x.o
|
||||
obj-$(CONFIG_AT91_ADC) += at91_adc.o
|
||||
obj-$(CONFIG_AXP288_ADC) += axp288_adc.o
|
||||
obj-$(CONFIG_EXYNOS_ADC) += exynos_adc.o
|
||||
obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
|
||||
obj-$(CONFIG_MAX1027) += max1027.o
|
||||
|
261
drivers/iio/adc/axp288_adc.c
Normal file
261
drivers/iio/adc/axp288_adc.c
Normal file
@ -0,0 +1,261 @@
|
||||
/*
|
||||
* axp288_adc.c - X-Powers AXP288 PMIC ADC Driver
|
||||
*
|
||||
* Copyright (C) 2014 Intel Corporation
|
||||
*
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
*
|
||||
* 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; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/mfd/axp20x.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/machine.h>
|
||||
#include <linux/iio/driver.h>
|
||||
|
||||
#define AXP288_ADC_EN_MASK 0xF1
|
||||
#define AXP288_ADC_TS_PIN_GPADC 0xF2
|
||||
#define AXP288_ADC_TS_PIN_ON 0xF3
|
||||
|
||||
enum axp288_adc_id {
|
||||
AXP288_ADC_TS,
|
||||
AXP288_ADC_PMIC,
|
||||
AXP288_ADC_GP,
|
||||
AXP288_ADC_BATT_CHRG_I,
|
||||
AXP288_ADC_BATT_DISCHRG_I,
|
||||
AXP288_ADC_BATT_V,
|
||||
AXP288_ADC_NR_CHAN,
|
||||
};
|
||||
|
||||
struct axp288_adc_info {
|
||||
int irq;
|
||||
struct regmap *regmap;
|
||||
};
|
||||
|
||||
static const struct iio_chan_spec const axp288_adc_channels[] = {
|
||||
{
|
||||
.indexed = 1,
|
||||
.type = IIO_TEMP,
|
||||
.channel = 0,
|
||||
.address = AXP288_TS_ADC_H,
|
||||
.datasheet_name = "TS_PIN",
|
||||
}, {
|
||||
.indexed = 1,
|
||||
.type = IIO_TEMP,
|
||||
.channel = 1,
|
||||
.address = AXP288_PMIC_ADC_H,
|
||||
.datasheet_name = "PMIC_TEMP",
|
||||
}, {
|
||||
.indexed = 1,
|
||||
.type = IIO_TEMP,
|
||||
.channel = 2,
|
||||
.address = AXP288_GP_ADC_H,
|
||||
.datasheet_name = "GPADC",
|
||||
}, {
|
||||
.indexed = 1,
|
||||
.type = IIO_CURRENT,
|
||||
.channel = 3,
|
||||
.address = AXP20X_BATT_CHRG_I_H,
|
||||
.datasheet_name = "BATT_CHG_I",
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
|
||||
}, {
|
||||
.indexed = 1,
|
||||
.type = IIO_CURRENT,
|
||||
.channel = 4,
|
||||
.address = AXP20X_BATT_DISCHRG_I_H,
|
||||
.datasheet_name = "BATT_DISCHRG_I",
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
|
||||
}, {
|
||||
.indexed = 1,
|
||||
.type = IIO_VOLTAGE,
|
||||
.channel = 5,
|
||||
.address = AXP20X_BATT_V_H,
|
||||
.datasheet_name = "BATT_V",
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
|
||||
},
|
||||
};
|
||||
|
||||
#define AXP288_ADC_MAP(_adc_channel_label, _consumer_dev_name, \
|
||||
_consumer_channel) \
|
||||
{ \
|
||||
.adc_channel_label = _adc_channel_label, \
|
||||
.consumer_dev_name = _consumer_dev_name, \
|
||||
.consumer_channel = _consumer_channel, \
|
||||
}
|
||||
|
||||
/* for consumer drivers */
|
||||
static struct iio_map axp288_adc_default_maps[] = {
|
||||
AXP288_ADC_MAP("TS_PIN", "axp288-batt", "axp288-batt-temp"),
|
||||
AXP288_ADC_MAP("PMIC_TEMP", "axp288-pmic", "axp288-pmic-temp"),
|
||||
AXP288_ADC_MAP("GPADC", "axp288-gpadc", "axp288-system-temp"),
|
||||
AXP288_ADC_MAP("BATT_CHG_I", "axp288-chrg", "axp288-chrg-curr"),
|
||||
AXP288_ADC_MAP("BATT_DISCHRG_I", "axp288-chrg", "axp288-chrg-d-curr"),
|
||||
AXP288_ADC_MAP("BATT_V", "axp288-batt", "axp288-batt-volt"),
|
||||
{},
|
||||
};
|
||||
|
||||
static int axp288_adc_read_channel(int *val, unsigned long address,
|
||||
struct regmap *regmap)
|
||||
{
|
||||
u8 buf[2];
|
||||
|
||||
if (regmap_bulk_read(regmap, address, buf, 2))
|
||||
return -EIO;
|
||||
*val = (buf[0] << 4) + ((buf[1] >> 4) & 0x0F);
|
||||
|
||||
return IIO_VAL_INT;
|
||||
}
|
||||
|
||||
static int axp288_adc_set_ts(struct regmap *regmap, unsigned int mode,
|
||||
unsigned long address)
|
||||
{
|
||||
/* channels other than GPADC do not need to switch TS pin */
|
||||
if (address != AXP288_GP_ADC_H)
|
||||
return 0;
|
||||
|
||||
return regmap_write(regmap, AXP288_ADC_TS_PIN_CTRL, mode);
|
||||
}
|
||||
|
||||
static int axp288_adc_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val, int *val2, long mask)
|
||||
{
|
||||
int ret;
|
||||
struct axp288_adc_info *info = iio_priv(indio_dev);
|
||||
|
||||
mutex_lock(&indio_dev->mlock);
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
if (axp288_adc_set_ts(info->regmap, AXP288_ADC_TS_PIN_GPADC,
|
||||
chan->address)) {
|
||||
dev_err(&indio_dev->dev, "GPADC mode\n");
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
ret = axp288_adc_read_channel(val, chan->address, info->regmap);
|
||||
if (axp288_adc_set_ts(info->regmap, AXP288_ADC_TS_PIN_ON,
|
||||
chan->address))
|
||||
dev_err(&indio_dev->dev, "TS pin restore\n");
|
||||
break;
|
||||
case IIO_CHAN_INFO_PROCESSED:
|
||||
ret = axp288_adc_read_channel(val, chan->address, info->regmap);
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
}
|
||||
mutex_unlock(&indio_dev->mlock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int axp288_adc_set_state(struct regmap *regmap)
|
||||
{
|
||||
/* ADC should be always enabled for internal FG to function */
|
||||
if (regmap_write(regmap, AXP288_ADC_TS_PIN_CTRL, AXP288_ADC_TS_PIN_ON))
|
||||
return -EIO;
|
||||
|
||||
return regmap_write(regmap, AXP20X_ADC_EN1, AXP288_ADC_EN_MASK);
|
||||
}
|
||||
|
||||
static const struct iio_info axp288_adc_iio_info = {
|
||||
.read_raw = &axp288_adc_read_raw,
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int axp288_adc_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
struct axp288_adc_info *info;
|
||||
struct iio_dev *indio_dev;
|
||||
struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
|
||||
|
||||
indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*info));
|
||||
if (!indio_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
info = iio_priv(indio_dev);
|
||||
info->irq = platform_get_irq(pdev, 0);
|
||||
if (info->irq < 0) {
|
||||
dev_err(&pdev->dev, "no irq resource?\n");
|
||||
return info->irq;
|
||||
}
|
||||
platform_set_drvdata(pdev, indio_dev);
|
||||
info->regmap = axp20x->regmap;
|
||||
/*
|
||||
* Set ADC to enabled state at all time, including system suspend.
|
||||
* otherwise internal fuel gauge functionality may be affected.
|
||||
*/
|
||||
ret = axp288_adc_set_state(axp20x->regmap);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "unable to enable ADC device\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
indio_dev->dev.parent = &pdev->dev;
|
||||
indio_dev->name = pdev->name;
|
||||
indio_dev->channels = axp288_adc_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(axp288_adc_channels);
|
||||
indio_dev->info = &axp288_adc_iio_info;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
ret = iio_map_array_register(indio_dev, axp288_adc_default_maps);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = iio_device_register(indio_dev);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "unable to register iio device\n");
|
||||
goto err_array_unregister;
|
||||
}
|
||||
return 0;
|
||||
|
||||
err_array_unregister:
|
||||
iio_map_array_unregister(indio_dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int axp288_adc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
|
||||
|
||||
iio_device_unregister(indio_dev);
|
||||
iio_map_array_unregister(indio_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_device_id axp288_adc_id_table[] = {
|
||||
{ .name = "axp288_adc" },
|
||||
{},
|
||||
};
|
||||
|
||||
static struct platform_driver axp288_adc_driver = {
|
||||
.probe = axp288_adc_probe,
|
||||
.remove = axp288_adc_remove,
|
||||
.id_table = axp288_adc_id_table,
|
||||
.driver = {
|
||||
.name = "axp288_adc",
|
||||
},
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(platform, axp288_adc_id_table);
|
||||
|
||||
module_platform_driver(axp288_adc_driver);
|
||||
|
||||
MODULE_AUTHOR("Jacob Pan <jacob.jun.pan@linux.intel.com>");
|
||||
MODULE_DESCRIPTION("X-Powers AXP288 ADC Driver");
|
||||
MODULE_LICENSE("GPL");
|
@ -59,6 +59,17 @@ config MFD_AAT2870_CORE
|
||||
additional drivers must be enabled in order to use the
|
||||
functionality of the device.
|
||||
|
||||
config MFD_ATMEL_HLCDC
|
||||
tristate "Atmel HLCDC (High-end LCD Controller)"
|
||||
select MFD_CORE
|
||||
select REGMAP_MMIO
|
||||
depends on OF
|
||||
help
|
||||
If you say yes here you get support for the HLCDC block.
|
||||
This driver provides common support for accessing the device,
|
||||
additional drivers must be enabled in order to use the
|
||||
functionality of the device.
|
||||
|
||||
config MFD_BCM590XX
|
||||
tristate "Broadcom BCM590xx PMUs"
|
||||
select MFD_CORE
|
||||
@ -74,7 +85,8 @@ config MFD_AXP20X
|
||||
select REGMAP_IRQ
|
||||
depends on I2C=y
|
||||
help
|
||||
If you say Y here you get support for the X-Powers AXP202 and AXP209.
|
||||
If you say Y here you get support for the X-Powers AXP202, AXP209 and
|
||||
AXP288 power management IC (PMIC).
|
||||
This driver include only the core APIs. You have to select individual
|
||||
components like regulators or the PEK (Power Enable Key) under the
|
||||
corresponding menus.
|
||||
@ -183,6 +195,16 @@ config MFD_DA9063
|
||||
Additional drivers must be enabled in order to use the functionality
|
||||
of the device.
|
||||
|
||||
config MFD_DLN2
|
||||
tristate "Diolan DLN2 support"
|
||||
select MFD_CORE
|
||||
depends on USB
|
||||
help
|
||||
This adds support for Diolan USB-I2C/SPI/GPIO Master Adapter
|
||||
DLN-2. Additional drivers such as I2C_DLN2, GPIO_DLN2,
|
||||
etc. must be enabled in order to use the functionality of
|
||||
the device.
|
||||
|
||||
config MFD_MC13XXX
|
||||
tristate
|
||||
depends on (SPI_MASTER || I2C)
|
||||
@ -655,7 +677,6 @@ config MFD_SEC_CORE
|
||||
select MFD_CORE
|
||||
select REGMAP_I2C
|
||||
select REGMAP_IRQ
|
||||
select REGULATOR
|
||||
help
|
||||
Support for the Samsung Electronics MFD series.
|
||||
This driver provides common support for accessing the device,
|
||||
|
@ -13,7 +13,7 @@ obj-$(CONFIG_MFD_CROS_EC) += cros_ec.o
|
||||
obj-$(CONFIG_MFD_CROS_EC_I2C) += cros_ec_i2c.o
|
||||
obj-$(CONFIG_MFD_CROS_EC_SPI) += cros_ec_spi.o
|
||||
|
||||
rtsx_pci-objs := rtsx_pcr.o rts5209.o rts5229.o rtl8411.o rts5227.o rts5249.o
|
||||
rtsx_pci-objs := rtsx_pcr.o rtsx_gops.o rts5209.o rts5229.o rtl8411.o rts5227.o rts5249.o
|
||||
obj-$(CONFIG_MFD_RTSX_PCI) += rtsx_pci.o
|
||||
obj-$(CONFIG_MFD_RTSX_USB) += rtsx_usb.o
|
||||
|
||||
@ -157,6 +157,7 @@ obj-$(CONFIG_MFD_SPMI_PMIC) += qcom-spmi-pmic.o
|
||||
obj-$(CONFIG_TPS65911_COMPARATOR) += tps65911-comparator.o
|
||||
obj-$(CONFIG_MFD_TPS65090) += tps65090.o
|
||||
obj-$(CONFIG_MFD_AAT2870_CORE) += aat2870-core.o
|
||||
obj-$(CONFIG_MFD_ATMEL_HLCDC) += atmel-hlcdc.o
|
||||
obj-$(CONFIG_MFD_INTEL_MSIC) += intel_msic.o
|
||||
obj-$(CONFIG_MFD_PALMAS) += palmas.o
|
||||
obj-$(CONFIG_MFD_VIPERBOARD) += viperboard.o
|
||||
@ -174,6 +175,7 @@ obj-$(CONFIG_MFD_STW481X) += stw481x.o
|
||||
obj-$(CONFIG_MFD_IPAQ_MICRO) += ipaq-micro.o
|
||||
obj-$(CONFIG_MFD_MENF21BMC) += menf21bmc.o
|
||||
obj-$(CONFIG_MFD_HI6421_PMIC) += hi6421-pmic-core.o
|
||||
obj-$(CONFIG_MFD_DLN2) += dln2.o
|
||||
|
||||
intel-soc-pmic-objs := intel_soc_pmic_core.o intel_soc_pmic_crc.o
|
||||
obj-$(CONFIG_INTEL_SOC_PMIC) += intel-soc-pmic.o
|
||||
|
@ -85,63 +85,6 @@ static void ab8500_power_off(void)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Use the AB WD to reset the platform. It will perform a hard
|
||||
* reset instead of a soft reset. Write the reset reason to
|
||||
* the AB before reset, which can be read upon restart.
|
||||
*/
|
||||
void ab8500_restart(char mode, const char *cmd)
|
||||
{
|
||||
struct ab8500_platform_data *plat;
|
||||
struct ab8500_sysctrl_platform_data *pdata;
|
||||
u16 reason = 0;
|
||||
u8 val;
|
||||
|
||||
if (sysctrl_dev == NULL) {
|
||||
pr_err("%s: sysctrl not initialized\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
plat = dev_get_platdata(sysctrl_dev->parent);
|
||||
pdata = plat->sysctrl;
|
||||
if (pdata && pdata->reboot_reason_code)
|
||||
reason = pdata->reboot_reason_code(cmd);
|
||||
else
|
||||
pr_warn("[%s] No reboot reason set. Default reason %d\n",
|
||||
__func__, reason);
|
||||
|
||||
/*
|
||||
* Disable RTC alarm, just a precaution so that no alarm
|
||||
* is running when WD reset is executed.
|
||||
*/
|
||||
abx500_get_register_interruptible(sysctrl_dev, AB8500_RTC,
|
||||
RTC_CTRL , &val);
|
||||
abx500_set_register_interruptible(sysctrl_dev, AB8500_RTC,
|
||||
RTC_CTRL , (val & ~RTC_ALARM_ENABLE));
|
||||
|
||||
/*
|
||||
* Android is not using the RTC alarm registers during reboot
|
||||
* so we borrow them for writing the reason of reset
|
||||
*/
|
||||
|
||||
/* reason[8 LSB] */
|
||||
val = reason & 0xFF;
|
||||
abx500_set_register_interruptible(sysctrl_dev, AB8500_RTC,
|
||||
AB8500_ALARM_MIN_LOW , val);
|
||||
|
||||
/* reason[8 MSB] */
|
||||
val = (reason>>8) & 0xFF;
|
||||
abx500_set_register_interruptible(sysctrl_dev, AB8500_RTC,
|
||||
AB8500_ALARM_MIN_MID , val);
|
||||
|
||||
/* Setting WD timeout to 0 */
|
||||
ab8500_sysctrl_write(AB8500_MAINWDOGTIMER, 0xFF, 0x0);
|
||||
|
||||
/* Setting the parameters to AB8500 WD*/
|
||||
ab8500_sysctrl_write(AB8500_MAINWDOGCTRL, 0xFF, (AB8500_ENABLE_WD |
|
||||
AB8500_WD_RESTART_ON_EXPIRE | AB8500_KICK_WD));
|
||||
}
|
||||
|
||||
static inline bool valid_bank(u8 bank)
|
||||
{
|
||||
return ((bank == AB8500_SYS_CTRL1_BLOCK) ||
|
||||
|
@ -75,7 +75,9 @@ static int arizona_spi_probe(struct spi_device *spi)
|
||||
static int arizona_spi_remove(struct spi_device *spi)
|
||||
{
|
||||
struct arizona *arizona = spi_get_drvdata(spi);
|
||||
|
||||
arizona_dev_exit(arizona);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
122
drivers/mfd/atmel-hlcdc.c
Normal file
122
drivers/mfd/atmel-hlcdc.c
Normal file
@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Free Electrons
|
||||
* Copyright (C) 2014 Atmel
|
||||
*
|
||||
* Author: Boris BREZILLON <boris.brezillon@free-electrons.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.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of 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. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/mfd/atmel-hlcdc.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#define ATMEL_HLCDC_REG_MAX (0x4000 - 0x4)
|
||||
|
||||
static const struct mfd_cell atmel_hlcdc_cells[] = {
|
||||
{
|
||||
.name = "atmel-hlcdc-pwm",
|
||||
.of_compatible = "atmel,hlcdc-pwm",
|
||||
},
|
||||
{
|
||||
.name = "atmel-hlcdc-dc",
|
||||
.of_compatible = "atmel,hlcdc-display-controller",
|
||||
},
|
||||
};
|
||||
|
||||
static const struct regmap_config atmel_hlcdc_regmap_config = {
|
||||
.reg_bits = 32,
|
||||
.val_bits = 32,
|
||||
.reg_stride = 4,
|
||||
.max_register = ATMEL_HLCDC_REG_MAX,
|
||||
};
|
||||
|
||||
static int atmel_hlcdc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct atmel_hlcdc *hlcdc;
|
||||
struct resource *res;
|
||||
void __iomem *regs;
|
||||
|
||||
hlcdc = devm_kzalloc(dev, sizeof(*hlcdc), GFP_KERNEL);
|
||||
if (!hlcdc)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
regs = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(regs))
|
||||
return PTR_ERR(regs);
|
||||
|
||||
hlcdc->irq = platform_get_irq(pdev, 0);
|
||||
if (hlcdc->irq < 0)
|
||||
return hlcdc->irq;
|
||||
|
||||
hlcdc->periph_clk = devm_clk_get(dev, "periph_clk");
|
||||
if (IS_ERR(hlcdc->periph_clk)) {
|
||||
dev_err(dev, "failed to get peripheral clock\n");
|
||||
return PTR_ERR(hlcdc->periph_clk);
|
||||
}
|
||||
|
||||
hlcdc->sys_clk = devm_clk_get(dev, "sys_clk");
|
||||
if (IS_ERR(hlcdc->sys_clk)) {
|
||||
dev_err(dev, "failed to get system clock\n");
|
||||
return PTR_ERR(hlcdc->sys_clk);
|
||||
}
|
||||
|
||||
hlcdc->slow_clk = devm_clk_get(dev, "slow_clk");
|
||||
if (IS_ERR(hlcdc->slow_clk)) {
|
||||
dev_err(dev, "failed to get slow clock\n");
|
||||
return PTR_ERR(hlcdc->slow_clk);
|
||||
}
|
||||
|
||||
hlcdc->regmap = devm_regmap_init_mmio(dev, regs,
|
||||
&atmel_hlcdc_regmap_config);
|
||||
if (IS_ERR(hlcdc->regmap))
|
||||
return PTR_ERR(hlcdc->regmap);
|
||||
|
||||
dev_set_drvdata(dev, hlcdc);
|
||||
|
||||
return mfd_add_devices(dev, -1, atmel_hlcdc_cells,
|
||||
ARRAY_SIZE(atmel_hlcdc_cells),
|
||||
NULL, 0, NULL);
|
||||
}
|
||||
|
||||
static int atmel_hlcdc_remove(struct platform_device *pdev)
|
||||
{
|
||||
mfd_remove_devices(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id atmel_hlcdc_match[] = {
|
||||
{ .compatible = "atmel,sama5d3-hlcdc" },
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
|
||||
static struct platform_driver atmel_hlcdc_driver = {
|
||||
.probe = atmel_hlcdc_probe,
|
||||
.remove = atmel_hlcdc_remove,
|
||||
.driver = {
|
||||
.name = "atmel-hlcdc",
|
||||
.of_match_table = atmel_hlcdc_match,
|
||||
},
|
||||
};
|
||||
module_platform_driver(atmel_hlcdc_driver);
|
||||
|
||||
MODULE_ALIAS("platform:atmel-hlcdc");
|
||||
MODULE_AUTHOR("Boris Brezillon <boris.brezillon@free-electrons.com>");
|
||||
MODULE_DESCRIPTION("Atmel HLCDC driver");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -1,9 +1,9 @@
|
||||
/*
|
||||
* axp20x.c - MFD core driver for the X-Powers AXP202 and AXP209
|
||||
* axp20x.c - MFD core driver for the X-Powers' Power Management ICs
|
||||
*
|
||||
* AXP20x comprises an adaptive USB-Compatible PWM charger, 2 BUCK DC-DC
|
||||
* converters, 5 LDOs, multiple 12-bit ADCs of voltage, current and temperature
|
||||
* as well as 4 configurable GPIOs.
|
||||
* AXP20x typically comprises an adaptive USB-Compatible PWM charger, BUCK DC-DC
|
||||
* converters, LDOs, multiple 12-bit ADCs of voltage, current and temperature
|
||||
* as well as configurable GPIOs.
|
||||
*
|
||||
* Author: Carlo Caione <carlo@caione.org>
|
||||
*
|
||||
@ -25,9 +25,16 @@
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/acpi.h>
|
||||
|
||||
#define AXP20X_OFF 0x80
|
||||
|
||||
static const char const *axp20x_model_names[] = {
|
||||
"AXP202",
|
||||
"AXP209",
|
||||
"AXP288",
|
||||
};
|
||||
|
||||
static const struct regmap_range axp20x_writeable_ranges[] = {
|
||||
regmap_reg_range(AXP20X_DATACACHE(0), AXP20X_IRQ5_STATE),
|
||||
regmap_reg_range(AXP20X_DCDC_MODE, AXP20X_FG_RES),
|
||||
@ -47,6 +54,25 @@ static const struct regmap_access_table axp20x_volatile_table = {
|
||||
.n_yes_ranges = ARRAY_SIZE(axp20x_volatile_ranges),
|
||||
};
|
||||
|
||||
static const struct regmap_range axp288_writeable_ranges[] = {
|
||||
regmap_reg_range(AXP20X_DATACACHE(0), AXP20X_IRQ6_STATE),
|
||||
regmap_reg_range(AXP20X_DCDC_MODE, AXP288_FG_TUNE5),
|
||||
};
|
||||
|
||||
static const struct regmap_range axp288_volatile_ranges[] = {
|
||||
regmap_reg_range(AXP20X_IRQ1_EN, AXP20X_IPSOUT_V_HIGH_L),
|
||||
};
|
||||
|
||||
static const struct regmap_access_table axp288_writeable_table = {
|
||||
.yes_ranges = axp288_writeable_ranges,
|
||||
.n_yes_ranges = ARRAY_SIZE(axp288_writeable_ranges),
|
||||
};
|
||||
|
||||
static const struct regmap_access_table axp288_volatile_table = {
|
||||
.yes_ranges = axp288_volatile_ranges,
|
||||
.n_yes_ranges = ARRAY_SIZE(axp288_volatile_ranges),
|
||||
};
|
||||
|
||||
static struct resource axp20x_pek_resources[] = {
|
||||
{
|
||||
.name = "PEK_DBR",
|
||||
@ -61,6 +87,39 @@ static struct resource axp20x_pek_resources[] = {
|
||||
},
|
||||
};
|
||||
|
||||
static struct resource axp288_battery_resources[] = {
|
||||
{
|
||||
.start = AXP288_IRQ_QWBTU,
|
||||
.end = AXP288_IRQ_QWBTU,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
{
|
||||
.start = AXP288_IRQ_WBTU,
|
||||
.end = AXP288_IRQ_WBTU,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
{
|
||||
.start = AXP288_IRQ_QWBTO,
|
||||
.end = AXP288_IRQ_QWBTO,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
{
|
||||
.start = AXP288_IRQ_WBTO,
|
||||
.end = AXP288_IRQ_WBTO,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
{
|
||||
.start = AXP288_IRQ_WL2,
|
||||
.end = AXP288_IRQ_WL2,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
{
|
||||
.start = AXP288_IRQ_WL1,
|
||||
.end = AXP288_IRQ_WL1,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct regmap_config axp20x_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
@ -70,47 +129,96 @@ static const struct regmap_config axp20x_regmap_config = {
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
};
|
||||
|
||||
#define AXP20X_IRQ(_irq, _off, _mask) \
|
||||
[AXP20X_IRQ_##_irq] = { .reg_offset = (_off), .mask = BIT(_mask) }
|
||||
static const struct regmap_config axp288_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.wr_table = &axp288_writeable_table,
|
||||
.volatile_table = &axp288_volatile_table,
|
||||
.max_register = AXP288_FG_TUNE5,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
};
|
||||
|
||||
#define INIT_REGMAP_IRQ(_variant, _irq, _off, _mask) \
|
||||
[_variant##_IRQ_##_irq] = { .reg_offset = (_off), .mask = BIT(_mask) }
|
||||
|
||||
static const struct regmap_irq axp20x_regmap_irqs[] = {
|
||||
AXP20X_IRQ(ACIN_OVER_V, 0, 7),
|
||||
AXP20X_IRQ(ACIN_PLUGIN, 0, 6),
|
||||
AXP20X_IRQ(ACIN_REMOVAL, 0, 5),
|
||||
AXP20X_IRQ(VBUS_OVER_V, 0, 4),
|
||||
AXP20X_IRQ(VBUS_PLUGIN, 0, 3),
|
||||
AXP20X_IRQ(VBUS_REMOVAL, 0, 2),
|
||||
AXP20X_IRQ(VBUS_V_LOW, 0, 1),
|
||||
AXP20X_IRQ(BATT_PLUGIN, 1, 7),
|
||||
AXP20X_IRQ(BATT_REMOVAL, 1, 6),
|
||||
AXP20X_IRQ(BATT_ENT_ACT_MODE, 1, 5),
|
||||
AXP20X_IRQ(BATT_EXIT_ACT_MODE, 1, 4),
|
||||
AXP20X_IRQ(CHARG, 1, 3),
|
||||
AXP20X_IRQ(CHARG_DONE, 1, 2),
|
||||
AXP20X_IRQ(BATT_TEMP_HIGH, 1, 1),
|
||||
AXP20X_IRQ(BATT_TEMP_LOW, 1, 0),
|
||||
AXP20X_IRQ(DIE_TEMP_HIGH, 2, 7),
|
||||
AXP20X_IRQ(CHARG_I_LOW, 2, 6),
|
||||
AXP20X_IRQ(DCDC1_V_LONG, 2, 5),
|
||||
AXP20X_IRQ(DCDC2_V_LONG, 2, 4),
|
||||
AXP20X_IRQ(DCDC3_V_LONG, 2, 3),
|
||||
AXP20X_IRQ(PEK_SHORT, 2, 1),
|
||||
AXP20X_IRQ(PEK_LONG, 2, 0),
|
||||
AXP20X_IRQ(N_OE_PWR_ON, 3, 7),
|
||||
AXP20X_IRQ(N_OE_PWR_OFF, 3, 6),
|
||||
AXP20X_IRQ(VBUS_VALID, 3, 5),
|
||||
AXP20X_IRQ(VBUS_NOT_VALID, 3, 4),
|
||||
AXP20X_IRQ(VBUS_SESS_VALID, 3, 3),
|
||||
AXP20X_IRQ(VBUS_SESS_END, 3, 2),
|
||||
AXP20X_IRQ(LOW_PWR_LVL1, 3, 1),
|
||||
AXP20X_IRQ(LOW_PWR_LVL2, 3, 0),
|
||||
AXP20X_IRQ(TIMER, 4, 7),
|
||||
AXP20X_IRQ(PEK_RIS_EDGE, 4, 6),
|
||||
AXP20X_IRQ(PEK_FAL_EDGE, 4, 5),
|
||||
AXP20X_IRQ(GPIO3_INPUT, 4, 3),
|
||||
AXP20X_IRQ(GPIO2_INPUT, 4, 2),
|
||||
AXP20X_IRQ(GPIO1_INPUT, 4, 1),
|
||||
AXP20X_IRQ(GPIO0_INPUT, 4, 0),
|
||||
INIT_REGMAP_IRQ(AXP20X, ACIN_OVER_V, 0, 7),
|
||||
INIT_REGMAP_IRQ(AXP20X, ACIN_PLUGIN, 0, 6),
|
||||
INIT_REGMAP_IRQ(AXP20X, ACIN_REMOVAL, 0, 5),
|
||||
INIT_REGMAP_IRQ(AXP20X, VBUS_OVER_V, 0, 4),
|
||||
INIT_REGMAP_IRQ(AXP20X, VBUS_PLUGIN, 0, 3),
|
||||
INIT_REGMAP_IRQ(AXP20X, VBUS_REMOVAL, 0, 2),
|
||||
INIT_REGMAP_IRQ(AXP20X, VBUS_V_LOW, 0, 1),
|
||||
INIT_REGMAP_IRQ(AXP20X, BATT_PLUGIN, 1, 7),
|
||||
INIT_REGMAP_IRQ(AXP20X, BATT_REMOVAL, 1, 6),
|
||||
INIT_REGMAP_IRQ(AXP20X, BATT_ENT_ACT_MODE, 1, 5),
|
||||
INIT_REGMAP_IRQ(AXP20X, BATT_EXIT_ACT_MODE, 1, 4),
|
||||
INIT_REGMAP_IRQ(AXP20X, CHARG, 1, 3),
|
||||
INIT_REGMAP_IRQ(AXP20X, CHARG_DONE, 1, 2),
|
||||
INIT_REGMAP_IRQ(AXP20X, BATT_TEMP_HIGH, 1, 1),
|
||||
INIT_REGMAP_IRQ(AXP20X, BATT_TEMP_LOW, 1, 0),
|
||||
INIT_REGMAP_IRQ(AXP20X, DIE_TEMP_HIGH, 2, 7),
|
||||
INIT_REGMAP_IRQ(AXP20X, CHARG_I_LOW, 2, 6),
|
||||
INIT_REGMAP_IRQ(AXP20X, DCDC1_V_LONG, 2, 5),
|
||||
INIT_REGMAP_IRQ(AXP20X, DCDC2_V_LONG, 2, 4),
|
||||
INIT_REGMAP_IRQ(AXP20X, DCDC3_V_LONG, 2, 3),
|
||||
INIT_REGMAP_IRQ(AXP20X, PEK_SHORT, 2, 1),
|
||||
INIT_REGMAP_IRQ(AXP20X, PEK_LONG, 2, 0),
|
||||
INIT_REGMAP_IRQ(AXP20X, N_OE_PWR_ON, 3, 7),
|
||||
INIT_REGMAP_IRQ(AXP20X, N_OE_PWR_OFF, 3, 6),
|
||||
INIT_REGMAP_IRQ(AXP20X, VBUS_VALID, 3, 5),
|
||||
INIT_REGMAP_IRQ(AXP20X, VBUS_NOT_VALID, 3, 4),
|
||||
INIT_REGMAP_IRQ(AXP20X, VBUS_SESS_VALID, 3, 3),
|
||||
INIT_REGMAP_IRQ(AXP20X, VBUS_SESS_END, 3, 2),
|
||||
INIT_REGMAP_IRQ(AXP20X, LOW_PWR_LVL1, 3, 1),
|
||||
INIT_REGMAP_IRQ(AXP20X, LOW_PWR_LVL2, 3, 0),
|
||||
INIT_REGMAP_IRQ(AXP20X, TIMER, 4, 7),
|
||||
INIT_REGMAP_IRQ(AXP20X, PEK_RIS_EDGE, 4, 6),
|
||||
INIT_REGMAP_IRQ(AXP20X, PEK_FAL_EDGE, 4, 5),
|
||||
INIT_REGMAP_IRQ(AXP20X, GPIO3_INPUT, 4, 3),
|
||||
INIT_REGMAP_IRQ(AXP20X, GPIO2_INPUT, 4, 2),
|
||||
INIT_REGMAP_IRQ(AXP20X, GPIO1_INPUT, 4, 1),
|
||||
INIT_REGMAP_IRQ(AXP20X, GPIO0_INPUT, 4, 0),
|
||||
};
|
||||
|
||||
/* some IRQs are compatible with axp20x models */
|
||||
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, DONE, 1, 2),
|
||||
INIT_REGMAP_IRQ(AXP288, CHARGING, 1, 3),
|
||||
INIT_REGMAP_IRQ(AXP288, SAFE_QUIT, 1, 4),
|
||||
INIT_REGMAP_IRQ(AXP288, SAFE_ENTER, 1, 5),
|
||||
INIT_REGMAP_IRQ(AXP288, ABSENT, 1, 6),
|
||||
INIT_REGMAP_IRQ(AXP288, APPEND, 1, 7),
|
||||
|
||||
INIT_REGMAP_IRQ(AXP288, QWBTU, 2, 0),
|
||||
INIT_REGMAP_IRQ(AXP288, WBTU, 2, 1),
|
||||
INIT_REGMAP_IRQ(AXP288, QWBTO, 2, 2),
|
||||
INIT_REGMAP_IRQ(AXP288, WBTO, 2, 3),
|
||||
INIT_REGMAP_IRQ(AXP288, QCBTU, 2, 4),
|
||||
INIT_REGMAP_IRQ(AXP288, CBTU, 2, 5),
|
||||
INIT_REGMAP_IRQ(AXP288, QCBTO, 2, 6),
|
||||
INIT_REGMAP_IRQ(AXP288, CBTO, 2, 7),
|
||||
|
||||
INIT_REGMAP_IRQ(AXP288, WL2, 3, 0),
|
||||
INIT_REGMAP_IRQ(AXP288, WL1, 3, 1),
|
||||
INIT_REGMAP_IRQ(AXP288, GPADC, 3, 2),
|
||||
INIT_REGMAP_IRQ(AXP288, OT, 3, 7),
|
||||
|
||||
INIT_REGMAP_IRQ(AXP288, GPIO0, 4, 0),
|
||||
INIT_REGMAP_IRQ(AXP288, GPIO1, 4, 1),
|
||||
INIT_REGMAP_IRQ(AXP288, POKO, 4, 2),
|
||||
INIT_REGMAP_IRQ(AXP288, POKL, 4, 3),
|
||||
INIT_REGMAP_IRQ(AXP288, POKS, 4, 4),
|
||||
INIT_REGMAP_IRQ(AXP288, POKN, 4, 5),
|
||||
INIT_REGMAP_IRQ(AXP288, POKP, 4, 6),
|
||||
INIT_REGMAP_IRQ(AXP288, TIMER, 4, 7),
|
||||
|
||||
INIT_REGMAP_IRQ(AXP288, MV_CHNG, 5, 0),
|
||||
INIT_REGMAP_IRQ(AXP288, BC_USB_CHNG, 5, 1),
|
||||
};
|
||||
|
||||
static const struct of_device_id axp20x_of_match[] = {
|
||||
@ -128,16 +236,39 @@ static const struct i2c_device_id axp20x_i2c_id[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, axp20x_i2c_id);
|
||||
|
||||
static const struct acpi_device_id axp20x_acpi_match[] = {
|
||||
{
|
||||
.id = "INT33F4",
|
||||
.driver_data = AXP288_ID,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, axp20x_acpi_match);
|
||||
|
||||
static const struct regmap_irq_chip axp20x_regmap_irq_chip = {
|
||||
.name = "axp20x_irq_chip",
|
||||
.status_base = AXP20X_IRQ1_STATE,
|
||||
.ack_base = AXP20X_IRQ1_STATE,
|
||||
.mask_base = AXP20X_IRQ1_EN,
|
||||
.num_regs = 5,
|
||||
.irqs = axp20x_regmap_irqs,
|
||||
.num_irqs = ARRAY_SIZE(axp20x_regmap_irqs),
|
||||
.mask_invert = true,
|
||||
.init_ack_masked = true,
|
||||
.irqs = axp20x_regmap_irqs,
|
||||
.num_irqs = ARRAY_SIZE(axp20x_regmap_irqs),
|
||||
.num_regs = 5,
|
||||
|
||||
};
|
||||
|
||||
static const struct regmap_irq_chip axp288_regmap_irq_chip = {
|
||||
.name = "axp288_irq_chip",
|
||||
.status_base = AXP20X_IRQ1_STATE,
|
||||
.ack_base = AXP20X_IRQ1_STATE,
|
||||
.mask_base = AXP20X_IRQ1_EN,
|
||||
.mask_invert = true,
|
||||
.init_ack_masked = true,
|
||||
.irqs = axp288_regmap_irqs,
|
||||
.num_irqs = ARRAY_SIZE(axp288_regmap_irqs),
|
||||
.num_regs = 6,
|
||||
|
||||
};
|
||||
|
||||
static struct mfd_cell axp20x_cells[] = {
|
||||
@ -150,36 +281,155 @@ static struct mfd_cell axp20x_cells[] = {
|
||||
},
|
||||
};
|
||||
|
||||
static struct resource axp288_adc_resources[] = {
|
||||
{
|
||||
.name = "GPADC",
|
||||
.start = AXP288_IRQ_GPADC,
|
||||
.end = AXP288_IRQ_GPADC,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
static struct resource axp288_charger_resources[] = {
|
||||
{
|
||||
.start = AXP288_IRQ_OV,
|
||||
.end = AXP288_IRQ_OV,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
{
|
||||
.start = AXP288_IRQ_DONE,
|
||||
.end = AXP288_IRQ_DONE,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
{
|
||||
.start = AXP288_IRQ_CHARGING,
|
||||
.end = AXP288_IRQ_CHARGING,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
{
|
||||
.start = AXP288_IRQ_SAFE_QUIT,
|
||||
.end = AXP288_IRQ_SAFE_QUIT,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
{
|
||||
.start = AXP288_IRQ_SAFE_ENTER,
|
||||
.end = AXP288_IRQ_SAFE_ENTER,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
{
|
||||
.start = AXP288_IRQ_QCBTU,
|
||||
.end = AXP288_IRQ_QCBTU,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
{
|
||||
.start = AXP288_IRQ_CBTU,
|
||||
.end = AXP288_IRQ_CBTU,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
{
|
||||
.start = AXP288_IRQ_QCBTO,
|
||||
.end = AXP288_IRQ_QCBTO,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
{
|
||||
.start = AXP288_IRQ_CBTO,
|
||||
.end = AXP288_IRQ_CBTO,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
static struct mfd_cell axp288_cells[] = {
|
||||
{
|
||||
.name = "axp288_adc",
|
||||
.num_resources = ARRAY_SIZE(axp288_adc_resources),
|
||||
.resources = axp288_adc_resources,
|
||||
},
|
||||
{
|
||||
.name = "axp288_charger",
|
||||
.num_resources = ARRAY_SIZE(axp288_charger_resources),
|
||||
.resources = axp288_charger_resources,
|
||||
},
|
||||
{
|
||||
.name = "axp288_battery",
|
||||
.num_resources = ARRAY_SIZE(axp288_battery_resources),
|
||||
.resources = axp288_battery_resources,
|
||||
},
|
||||
};
|
||||
|
||||
static struct axp20x_dev *axp20x_pm_power_off;
|
||||
static void axp20x_power_off(void)
|
||||
{
|
||||
if (axp20x_pm_power_off->variant == AXP288_ID)
|
||||
return;
|
||||
|
||||
regmap_write(axp20x_pm_power_off->regmap, AXP20X_OFF_CTRL,
|
||||
AXP20X_OFF);
|
||||
}
|
||||
|
||||
static int axp20x_match_device(struct axp20x_dev *axp20x, struct device *dev)
|
||||
{
|
||||
const struct acpi_device_id *acpi_id;
|
||||
const struct of_device_id *of_id;
|
||||
|
||||
if (dev->of_node) {
|
||||
of_id = of_match_device(axp20x_of_match, dev);
|
||||
if (!of_id) {
|
||||
dev_err(dev, "Unable to match OF ID\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
axp20x->variant = (long) of_id->data;
|
||||
} else {
|
||||
acpi_id = acpi_match_device(dev->driver->acpi_match_table, dev);
|
||||
if (!acpi_id || !acpi_id->driver_data) {
|
||||
dev_err(dev, "Unable to match ACPI ID and data\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
axp20x->variant = (long) acpi_id->driver_data;
|
||||
}
|
||||
|
||||
switch (axp20x->variant) {
|
||||
case AXP202_ID:
|
||||
case AXP209_ID:
|
||||
axp20x->nr_cells = ARRAY_SIZE(axp20x_cells);
|
||||
axp20x->cells = axp20x_cells;
|
||||
axp20x->regmap_cfg = &axp20x_regmap_config;
|
||||
axp20x->regmap_irq_chip = &axp20x_regmap_irq_chip;
|
||||
break;
|
||||
case AXP288_ID:
|
||||
axp20x->cells = axp288_cells;
|
||||
axp20x->nr_cells = ARRAY_SIZE(axp288_cells);
|
||||
axp20x->regmap_cfg = &axp288_regmap_config;
|
||||
axp20x->regmap_irq_chip = &axp288_regmap_irq_chip;
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "unsupported AXP20X ID %lu\n", axp20x->variant);
|
||||
return -EINVAL;
|
||||
}
|
||||
dev_info(dev, "AXP20x variant %s found\n",
|
||||
axp20x_model_names[axp20x->variant]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int axp20x_i2c_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct axp20x_dev *axp20x;
|
||||
const struct of_device_id *of_id;
|
||||
int ret;
|
||||
|
||||
axp20x = devm_kzalloc(&i2c->dev, sizeof(*axp20x), GFP_KERNEL);
|
||||
if (!axp20x)
|
||||
return -ENOMEM;
|
||||
|
||||
of_id = of_match_device(axp20x_of_match, &i2c->dev);
|
||||
if (!of_id) {
|
||||
dev_err(&i2c->dev, "Unable to setup AXP20X data\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
axp20x->variant = (long) of_id->data;
|
||||
ret = axp20x_match_device(axp20x, &i2c->dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
axp20x->i2c_client = i2c;
|
||||
axp20x->dev = &i2c->dev;
|
||||
dev_set_drvdata(axp20x->dev, axp20x);
|
||||
|
||||
axp20x->regmap = devm_regmap_init_i2c(i2c, &axp20x_regmap_config);
|
||||
axp20x->regmap = devm_regmap_init_i2c(i2c, axp20x->regmap_cfg);
|
||||
if (IS_ERR(axp20x->regmap)) {
|
||||
ret = PTR_ERR(axp20x->regmap);
|
||||
dev_err(&i2c->dev, "regmap init failed: %d\n", ret);
|
||||
@ -188,15 +438,15 @@ static int axp20x_i2c_probe(struct i2c_client *i2c,
|
||||
|
||||
ret = regmap_add_irq_chip(axp20x->regmap, i2c->irq,
|
||||
IRQF_ONESHOT | IRQF_SHARED, -1,
|
||||
&axp20x_regmap_irq_chip,
|
||||
axp20x->regmap_irq_chip,
|
||||
&axp20x->regmap_irqc);
|
||||
if (ret) {
|
||||
dev_err(&i2c->dev, "failed to add irq chip: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = mfd_add_devices(axp20x->dev, -1, axp20x_cells,
|
||||
ARRAY_SIZE(axp20x_cells), NULL, 0, NULL);
|
||||
ret = mfd_add_devices(axp20x->dev, -1, axp20x->cells,
|
||||
axp20x->nr_cells, NULL, 0, NULL);
|
||||
|
||||
if (ret) {
|
||||
dev_err(&i2c->dev, "failed to add MFD devices: %d\n", ret);
|
||||
@ -234,6 +484,7 @@ static struct i2c_driver axp20x_i2c_driver = {
|
||||
.name = "axp20x",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(axp20x_of_match),
|
||||
.acpi_match_table = ACPI_PTR(axp20x_acpi_match),
|
||||
},
|
||||
.probe = axp20x_i2c_probe,
|
||||
.remove = axp20x_i2c_remove,
|
||||
|
@ -118,7 +118,7 @@ int da9063_device_init(struct da9063 *da9063, unsigned int irq)
|
||||
da9063->irq_base = pdata->irq_base;
|
||||
} else {
|
||||
da9063->flags = 0;
|
||||
da9063->irq_base = 0;
|
||||
da9063->irq_base = -1;
|
||||
}
|
||||
da9063->chip_irq = irq;
|
||||
|
||||
@ -168,6 +168,8 @@ int da9063_device_init(struct da9063 *da9063, unsigned int irq)
|
||||
return ret;
|
||||
}
|
||||
|
||||
da9063->irq_base = regmap_irq_chip_get_base(da9063->regmap_irq);
|
||||
|
||||
ret = mfd_add_devices(da9063->dev, -1, da9063_devs,
|
||||
ARRAY_SIZE(da9063_devs), NULL, da9063->irq_base,
|
||||
NULL);
|
||||
|
@ -3150,23 +3150,28 @@ static int db8500_prcmu_probe(struct platform_device *pdev)
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "prcmu");
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev, "no prcmu memory region provided\n");
|
||||
return -ENOENT;
|
||||
return -EINVAL;
|
||||
}
|
||||
prcmu_base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
|
||||
if (!prcmu_base) {
|
||||
dev_err(&pdev->dev,
|
||||
"failed to ioremap prcmu register memory\n");
|
||||
return -ENOENT;
|
||||
return -ENOMEM;
|
||||
}
|
||||
init_prcm_registers();
|
||||
dbx500_fw_version_init(pdev, pdata->version_offset);
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "prcmu-tcdm");
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev, "no prcmu tcdm region provided\n");
|
||||
return -ENOENT;
|
||||
return -EINVAL;
|
||||
}
|
||||
tcdm_base = devm_ioremap(&pdev->dev, res->start,
|
||||
resource_size(res));
|
||||
if (!tcdm_base) {
|
||||
dev_err(&pdev->dev,
|
||||
"failed to ioremap prcmu-tcdm register memory\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Clean up the mailbox interrupts after pre-kernel code. */
|
||||
writel(ALL_MBOX_BITS, PRCM_ARM_IT1_CLR);
|
||||
@ -3174,15 +3179,14 @@ static int db8500_prcmu_probe(struct platform_device *pdev)
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq <= 0) {
|
||||
dev_err(&pdev->dev, "no prcmu irq provided\n");
|
||||
return -ENOENT;
|
||||
return irq;
|
||||
}
|
||||
|
||||
err = request_threaded_irq(irq, prcmu_irq_handler,
|
||||
prcmu_irq_thread_fn, IRQF_NO_SUSPEND, "prcmu", NULL);
|
||||
if (err < 0) {
|
||||
pr_err("prcmu: Failed to allocate IRQ_DB8500_PRCMU1.\n");
|
||||
err = -EBUSY;
|
||||
goto no_irq_return;
|
||||
return err;
|
||||
}
|
||||
|
||||
db8500_irq_init(np);
|
||||
@ -3206,7 +3210,7 @@ static int db8500_prcmu_probe(struct platform_device *pdev)
|
||||
if (err) {
|
||||
mfd_remove_devices(&pdev->dev);
|
||||
pr_err("prcmu: Failed to add subdevices\n");
|
||||
goto no_irq_return;
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
@ -3214,12 +3218,10 @@ static int db8500_prcmu_probe(struct platform_device *pdev)
|
||||
if (err) {
|
||||
mfd_remove_devices(&pdev->dev);
|
||||
pr_err("prcmu: Failed to add ab8500 subdevice\n");
|
||||
goto no_irq_return;
|
||||
return err;
|
||||
}
|
||||
|
||||
pr_info("DB8500 PRCMU initialized\n");
|
||||
|
||||
no_irq_return:
|
||||
return err;
|
||||
}
|
||||
static const struct of_device_id db8500_prcmu_match[] = {
|
||||
|
781
drivers/mfd/dln2.c
Normal file
781
drivers/mfd/dln2.c
Normal file
@ -0,0 +1,781 @@
|
||||
/*
|
||||
* Driver for the Diolan DLN-2 USB adapter
|
||||
*
|
||||
* Copyright (c) 2014 Intel Corporation
|
||||
*
|
||||
* Derived from:
|
||||
* i2c-diolan-u2c.c
|
||||
* Copyright (c) 2010-2011 Ericsson AB
|
||||
*
|
||||
* 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, version 2.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/dln2.h>
|
||||
#include <linux/rculist.h>
|
||||
|
||||
struct dln2_header {
|
||||
__le16 size;
|
||||
__le16 id;
|
||||
__le16 echo;
|
||||
__le16 handle;
|
||||
};
|
||||
|
||||
struct dln2_response {
|
||||
struct dln2_header hdr;
|
||||
__le16 result;
|
||||
};
|
||||
|
||||
#define DLN2_GENERIC_MODULE_ID 0x00
|
||||
#define DLN2_GENERIC_CMD(cmd) DLN2_CMD(cmd, DLN2_GENERIC_MODULE_ID)
|
||||
#define CMD_GET_DEVICE_VER DLN2_GENERIC_CMD(0x30)
|
||||
#define CMD_GET_DEVICE_SN DLN2_GENERIC_CMD(0x31)
|
||||
|
||||
#define DLN2_HW_ID 0x200
|
||||
#define DLN2_USB_TIMEOUT 200 /* in ms */
|
||||
#define DLN2_MAX_RX_SLOTS 16
|
||||
#define DLN2_MAX_URBS 16
|
||||
#define DLN2_RX_BUF_SIZE 512
|
||||
|
||||
enum dln2_handle {
|
||||
DLN2_HANDLE_EVENT = 0, /* don't change, hardware defined */
|
||||
DLN2_HANDLE_CTRL,
|
||||
DLN2_HANDLE_GPIO,
|
||||
DLN2_HANDLE_I2C,
|
||||
DLN2_HANDLE_SPI,
|
||||
DLN2_HANDLES
|
||||
};
|
||||
|
||||
/*
|
||||
* Receive context used between the receive demultiplexer and the transfer
|
||||
* routine. While sending a request the transfer routine will look for a free
|
||||
* receive context and use it to wait for a response and to receive the URB and
|
||||
* thus the response data.
|
||||
*/
|
||||
struct dln2_rx_context {
|
||||
/* completion used to wait for a response */
|
||||
struct completion done;
|
||||
|
||||
/* if non-NULL the URB contains the response */
|
||||
struct urb *urb;
|
||||
|
||||
/* if true then this context is used to wait for a response */
|
||||
bool in_use;
|
||||
};
|
||||
|
||||
/*
|
||||
* Receive contexts for a particular DLN2 module (i2c, gpio, etc.). We use the
|
||||
* handle header field to identify the module in dln2_dev.mod_rx_slots and then
|
||||
* the echo header field to index the slots field and find the receive context
|
||||
* for a particular request.
|
||||
*/
|
||||
struct dln2_mod_rx_slots {
|
||||
/* RX slots bitmap */
|
||||
DECLARE_BITMAP(bmap, DLN2_MAX_RX_SLOTS);
|
||||
|
||||
/* used to wait for a free RX slot */
|
||||
wait_queue_head_t wq;
|
||||
|
||||
/* used to wait for an RX operation to complete */
|
||||
struct dln2_rx_context slots[DLN2_MAX_RX_SLOTS];
|
||||
|
||||
/* avoid races between alloc/free_rx_slot and dln2_rx_transfer */
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
struct dln2_dev {
|
||||
struct usb_device *usb_dev;
|
||||
struct usb_interface *interface;
|
||||
u8 ep_in;
|
||||
u8 ep_out;
|
||||
|
||||
struct urb *rx_urb[DLN2_MAX_URBS];
|
||||
void *rx_buf[DLN2_MAX_URBS];
|
||||
|
||||
struct dln2_mod_rx_slots mod_rx_slots[DLN2_HANDLES];
|
||||
|
||||
struct list_head event_cb_list;
|
||||
spinlock_t event_cb_lock;
|
||||
|
||||
bool disconnect;
|
||||
int active_transfers;
|
||||
wait_queue_head_t disconnect_wq;
|
||||
spinlock_t disconnect_lock;
|
||||
};
|
||||
|
||||
struct dln2_event_cb_entry {
|
||||
struct list_head list;
|
||||
u16 id;
|
||||
struct platform_device *pdev;
|
||||
dln2_event_cb_t callback;
|
||||
};
|
||||
|
||||
int dln2_register_event_cb(struct platform_device *pdev, u16 id,
|
||||
dln2_event_cb_t event_cb)
|
||||
{
|
||||
struct dln2_dev *dln2 = dev_get_drvdata(pdev->dev.parent);
|
||||
struct dln2_event_cb_entry *i, *entry;
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
|
||||
entry = kzalloc(sizeof(*entry), GFP_KERNEL);
|
||||
if (!entry)
|
||||
return -ENOMEM;
|
||||
|
||||
entry->id = id;
|
||||
entry->callback = event_cb;
|
||||
entry->pdev = pdev;
|
||||
|
||||
spin_lock_irqsave(&dln2->event_cb_lock, flags);
|
||||
|
||||
list_for_each_entry(i, &dln2->event_cb_list, list) {
|
||||
if (i->id == id) {
|
||||
ret = -EBUSY;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ret)
|
||||
list_add_rcu(&entry->list, &dln2->event_cb_list);
|
||||
|
||||
spin_unlock_irqrestore(&dln2->event_cb_lock, flags);
|
||||
|
||||
if (ret)
|
||||
kfree(entry);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(dln2_register_event_cb);
|
||||
|
||||
void dln2_unregister_event_cb(struct platform_device *pdev, u16 id)
|
||||
{
|
||||
struct dln2_dev *dln2 = dev_get_drvdata(pdev->dev.parent);
|
||||
struct dln2_event_cb_entry *i;
|
||||
unsigned long flags;
|
||||
bool found = false;
|
||||
|
||||
spin_lock_irqsave(&dln2->event_cb_lock, flags);
|
||||
|
||||
list_for_each_entry(i, &dln2->event_cb_list, list) {
|
||||
if (i->id == id) {
|
||||
list_del_rcu(&i->list);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&dln2->event_cb_lock, flags);
|
||||
|
||||
if (found) {
|
||||
synchronize_rcu();
|
||||
kfree(i);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(dln2_unregister_event_cb);
|
||||
|
||||
/*
|
||||
* Returns true if a valid transfer slot is found. In this case the URB must not
|
||||
* be resubmitted immediately in dln2_rx as we need the data when dln2_transfer
|
||||
* is woke up. It will be resubmitted there.
|
||||
*/
|
||||
static bool dln2_transfer_complete(struct dln2_dev *dln2, struct urb *urb,
|
||||
u16 handle, u16 rx_slot)
|
||||
{
|
||||
struct device *dev = &dln2->interface->dev;
|
||||
struct dln2_mod_rx_slots *rxs = &dln2->mod_rx_slots[handle];
|
||||
struct dln2_rx_context *rxc;
|
||||
bool valid_slot = false;
|
||||
|
||||
if (rx_slot >= DLN2_MAX_RX_SLOTS)
|
||||
goto out;
|
||||
|
||||
rxc = &rxs->slots[rx_slot];
|
||||
|
||||
/*
|
||||
* No need to disable interrupts as this lock is not taken in interrupt
|
||||
* context elsewhere in this driver. This function (or its callers) are
|
||||
* also not exported to other modules.
|
||||
*/
|
||||
spin_lock(&rxs->lock);
|
||||
if (rxc->in_use && !rxc->urb) {
|
||||
rxc->urb = urb;
|
||||
complete(&rxc->done);
|
||||
valid_slot = true;
|
||||
}
|
||||
spin_unlock(&rxs->lock);
|
||||
|
||||
out:
|
||||
if (!valid_slot)
|
||||
dev_warn(dev, "bad/late response %d/%d\n", handle, rx_slot);
|
||||
|
||||
return valid_slot;
|
||||
}
|
||||
|
||||
static void dln2_run_event_callbacks(struct dln2_dev *dln2, u16 id, u16 echo,
|
||||
void *data, int len)
|
||||
{
|
||||
struct dln2_event_cb_entry *i;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
list_for_each_entry_rcu(i, &dln2->event_cb_list, list) {
|
||||
if (i->id == id) {
|
||||
i->callback(i->pdev, echo, data, len);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
static void dln2_rx(struct urb *urb)
|
||||
{
|
||||
struct dln2_dev *dln2 = urb->context;
|
||||
struct dln2_header *hdr = urb->transfer_buffer;
|
||||
struct device *dev = &dln2->interface->dev;
|
||||
u16 id, echo, handle, size;
|
||||
u8 *data;
|
||||
int len;
|
||||
int err;
|
||||
|
||||
switch (urb->status) {
|
||||
case 0:
|
||||
/* success */
|
||||
break;
|
||||
case -ECONNRESET:
|
||||
case -ENOENT:
|
||||
case -ESHUTDOWN:
|
||||
case -EPIPE:
|
||||
/* this urb is terminated, clean up */
|
||||
dev_dbg(dev, "urb shutting down with status %d\n", urb->status);
|
||||
return;
|
||||
default:
|
||||
dev_dbg(dev, "nonzero urb status received %d\n", urb->status);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (urb->actual_length < sizeof(struct dln2_header)) {
|
||||
dev_err(dev, "short response: %d\n", urb->actual_length);
|
||||
goto out;
|
||||
}
|
||||
|
||||
handle = le16_to_cpu(hdr->handle);
|
||||
id = le16_to_cpu(hdr->id);
|
||||
echo = le16_to_cpu(hdr->echo);
|
||||
size = le16_to_cpu(hdr->size);
|
||||
|
||||
if (size != urb->actual_length) {
|
||||
dev_err(dev, "size mismatch: handle %x cmd %x echo %x size %d actual %d\n",
|
||||
handle, id, echo, size, urb->actual_length);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (handle >= DLN2_HANDLES) {
|
||||
dev_warn(dev, "invalid handle %d\n", handle);
|
||||
goto out;
|
||||
}
|
||||
|
||||
data = urb->transfer_buffer + sizeof(struct dln2_header);
|
||||
len = urb->actual_length - sizeof(struct dln2_header);
|
||||
|
||||
if (handle == DLN2_HANDLE_EVENT) {
|
||||
dln2_run_event_callbacks(dln2, id, echo, data, len);
|
||||
} else {
|
||||
/* URB will be re-submitted in _dln2_transfer (free_rx_slot) */
|
||||
if (dln2_transfer_complete(dln2, urb, handle, echo))
|
||||
return;
|
||||
}
|
||||
|
||||
out:
|
||||
err = usb_submit_urb(urb, GFP_ATOMIC);
|
||||
if (err < 0)
|
||||
dev_err(dev, "failed to resubmit RX URB: %d\n", err);
|
||||
}
|
||||
|
||||
static void *dln2_prep_buf(u16 handle, u16 cmd, u16 echo, const void *obuf,
|
||||
int *obuf_len, gfp_t gfp)
|
||||
{
|
||||
int len;
|
||||
void *buf;
|
||||
struct dln2_header *hdr;
|
||||
|
||||
len = *obuf_len + sizeof(*hdr);
|
||||
buf = kmalloc(len, gfp);
|
||||
if (!buf)
|
||||
return NULL;
|
||||
|
||||
hdr = (struct dln2_header *)buf;
|
||||
hdr->id = cpu_to_le16(cmd);
|
||||
hdr->size = cpu_to_le16(len);
|
||||
hdr->echo = cpu_to_le16(echo);
|
||||
hdr->handle = cpu_to_le16(handle);
|
||||
|
||||
memcpy(buf + sizeof(*hdr), obuf, *obuf_len);
|
||||
|
||||
*obuf_len = len;
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static int dln2_send_wait(struct dln2_dev *dln2, u16 handle, u16 cmd, u16 echo,
|
||||
const void *obuf, int obuf_len)
|
||||
{
|
||||
int ret = 0;
|
||||
int len = obuf_len;
|
||||
void *buf;
|
||||
int actual;
|
||||
|
||||
buf = dln2_prep_buf(handle, cmd, echo, obuf, &len, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = usb_bulk_msg(dln2->usb_dev,
|
||||
usb_sndbulkpipe(dln2->usb_dev, dln2->ep_out),
|
||||
buf, len, &actual, DLN2_USB_TIMEOUT);
|
||||
|
||||
kfree(buf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool find_free_slot(struct dln2_dev *dln2, u16 handle, int *slot)
|
||||
{
|
||||
struct dln2_mod_rx_slots *rxs;
|
||||
unsigned long flags;
|
||||
|
||||
if (dln2->disconnect) {
|
||||
*slot = -ENODEV;
|
||||
return true;
|
||||
}
|
||||
|
||||
rxs = &dln2->mod_rx_slots[handle];
|
||||
|
||||
spin_lock_irqsave(&rxs->lock, flags);
|
||||
|
||||
*slot = find_first_zero_bit(rxs->bmap, DLN2_MAX_RX_SLOTS);
|
||||
|
||||
if (*slot < DLN2_MAX_RX_SLOTS) {
|
||||
struct dln2_rx_context *rxc = &rxs->slots[*slot];
|
||||
|
||||
set_bit(*slot, rxs->bmap);
|
||||
rxc->in_use = true;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&rxs->lock, flags);
|
||||
|
||||
return *slot < DLN2_MAX_RX_SLOTS;
|
||||
}
|
||||
|
||||
static int alloc_rx_slot(struct dln2_dev *dln2, u16 handle)
|
||||
{
|
||||
int ret;
|
||||
int slot;
|
||||
|
||||
/*
|
||||
* No need to timeout here, the wait is bounded by the timeout in
|
||||
* _dln2_transfer.
|
||||
*/
|
||||
ret = wait_event_interruptible(dln2->mod_rx_slots[handle].wq,
|
||||
find_free_slot(dln2, handle, &slot));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return slot;
|
||||
}
|
||||
|
||||
static void free_rx_slot(struct dln2_dev *dln2, u16 handle, int slot)
|
||||
{
|
||||
struct dln2_mod_rx_slots *rxs;
|
||||
struct urb *urb = NULL;
|
||||
unsigned long flags;
|
||||
struct dln2_rx_context *rxc;
|
||||
|
||||
rxs = &dln2->mod_rx_slots[handle];
|
||||
|
||||
spin_lock_irqsave(&rxs->lock, flags);
|
||||
|
||||
clear_bit(slot, rxs->bmap);
|
||||
|
||||
rxc = &rxs->slots[slot];
|
||||
rxc->in_use = false;
|
||||
urb = rxc->urb;
|
||||
rxc->urb = NULL;
|
||||
reinit_completion(&rxc->done);
|
||||
|
||||
spin_unlock_irqrestore(&rxs->lock, flags);
|
||||
|
||||
if (urb) {
|
||||
int err;
|
||||
struct device *dev = &dln2->interface->dev;
|
||||
|
||||
err = usb_submit_urb(urb, GFP_KERNEL);
|
||||
if (err < 0)
|
||||
dev_err(dev, "failed to resubmit RX URB: %d\n", err);
|
||||
}
|
||||
|
||||
wake_up_interruptible(&rxs->wq);
|
||||
}
|
||||
|
||||
static int _dln2_transfer(struct dln2_dev *dln2, u16 handle, u16 cmd,
|
||||
const void *obuf, unsigned obuf_len,
|
||||
void *ibuf, unsigned *ibuf_len)
|
||||
{
|
||||
int ret = 0;
|
||||
int rx_slot;
|
||||
struct dln2_response *rsp;
|
||||
struct dln2_rx_context *rxc;
|
||||
struct device *dev = &dln2->interface->dev;
|
||||
const unsigned long timeout = DLN2_USB_TIMEOUT * HZ / 1000;
|
||||
struct dln2_mod_rx_slots *rxs = &dln2->mod_rx_slots[handle];
|
||||
int size;
|
||||
|
||||
spin_lock(&dln2->disconnect_lock);
|
||||
if (!dln2->disconnect)
|
||||
dln2->active_transfers++;
|
||||
else
|
||||
ret = -ENODEV;
|
||||
spin_unlock(&dln2->disconnect_lock);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
rx_slot = alloc_rx_slot(dln2, handle);
|
||||
if (rx_slot < 0) {
|
||||
ret = rx_slot;
|
||||
goto out_decr;
|
||||
}
|
||||
|
||||
ret = dln2_send_wait(dln2, handle, cmd, rx_slot, obuf, obuf_len);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "USB write failed: %d\n", ret);
|
||||
goto out_free_rx_slot;
|
||||
}
|
||||
|
||||
rxc = &rxs->slots[rx_slot];
|
||||
|
||||
ret = wait_for_completion_interruptible_timeout(&rxc->done, timeout);
|
||||
if (ret <= 0) {
|
||||
if (!ret)
|
||||
ret = -ETIMEDOUT;
|
||||
goto out_free_rx_slot;
|
||||
} else {
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
if (dln2->disconnect) {
|
||||
ret = -ENODEV;
|
||||
goto out_free_rx_slot;
|
||||
}
|
||||
|
||||
/* if we got here we know that the response header has been checked */
|
||||
rsp = rxc->urb->transfer_buffer;
|
||||
size = le16_to_cpu(rsp->hdr.size);
|
||||
|
||||
if (size < sizeof(*rsp)) {
|
||||
ret = -EPROTO;
|
||||
goto out_free_rx_slot;
|
||||
}
|
||||
|
||||
if (le16_to_cpu(rsp->result) > 0x80) {
|
||||
dev_dbg(dev, "%d received response with error %d\n",
|
||||
handle, le16_to_cpu(rsp->result));
|
||||
ret = -EREMOTEIO;
|
||||
goto out_free_rx_slot;
|
||||
}
|
||||
|
||||
if (!ibuf)
|
||||
goto out_free_rx_slot;
|
||||
|
||||
if (*ibuf_len > size - sizeof(*rsp))
|
||||
*ibuf_len = size - sizeof(*rsp);
|
||||
|
||||
memcpy(ibuf, rsp + 1, *ibuf_len);
|
||||
|
||||
out_free_rx_slot:
|
||||
free_rx_slot(dln2, handle, rx_slot);
|
||||
out_decr:
|
||||
spin_lock(&dln2->disconnect_lock);
|
||||
dln2->active_transfers--;
|
||||
spin_unlock(&dln2->disconnect_lock);
|
||||
if (dln2->disconnect)
|
||||
wake_up(&dln2->disconnect_wq);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int dln2_transfer(struct platform_device *pdev, u16 cmd,
|
||||
const void *obuf, unsigned obuf_len,
|
||||
void *ibuf, unsigned *ibuf_len)
|
||||
{
|
||||
struct dln2_platform_data *dln2_pdata;
|
||||
struct dln2_dev *dln2;
|
||||
u16 handle;
|
||||
|
||||
dln2 = dev_get_drvdata(pdev->dev.parent);
|
||||
dln2_pdata = dev_get_platdata(&pdev->dev);
|
||||
handle = dln2_pdata->handle;
|
||||
|
||||
return _dln2_transfer(dln2, handle, cmd, obuf, obuf_len, ibuf,
|
||||
ibuf_len);
|
||||
}
|
||||
EXPORT_SYMBOL(dln2_transfer);
|
||||
|
||||
static int dln2_check_hw(struct dln2_dev *dln2)
|
||||
{
|
||||
int ret;
|
||||
__le32 hw_type;
|
||||
int len = sizeof(hw_type);
|
||||
|
||||
ret = _dln2_transfer(dln2, DLN2_HANDLE_CTRL, CMD_GET_DEVICE_VER,
|
||||
NULL, 0, &hw_type, &len);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (len < sizeof(hw_type))
|
||||
return -EREMOTEIO;
|
||||
|
||||
if (le32_to_cpu(hw_type) != DLN2_HW_ID) {
|
||||
dev_err(&dln2->interface->dev, "Device ID 0x%x not supported\n",
|
||||
le32_to_cpu(hw_type));
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dln2_print_serialno(struct dln2_dev *dln2)
|
||||
{
|
||||
int ret;
|
||||
__le32 serial_no;
|
||||
int len = sizeof(serial_no);
|
||||
struct device *dev = &dln2->interface->dev;
|
||||
|
||||
ret = _dln2_transfer(dln2, DLN2_HANDLE_CTRL, CMD_GET_DEVICE_SN, NULL, 0,
|
||||
&serial_no, &len);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (len < sizeof(serial_no))
|
||||
return -EREMOTEIO;
|
||||
|
||||
dev_info(dev, "Diolan DLN2 serial %u\n", le32_to_cpu(serial_no));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dln2_hw_init(struct dln2_dev *dln2)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = dln2_check_hw(dln2);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return dln2_print_serialno(dln2);
|
||||
}
|
||||
|
||||
static void dln2_free_rx_urbs(struct dln2_dev *dln2)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < DLN2_MAX_URBS; i++) {
|
||||
usb_kill_urb(dln2->rx_urb[i]);
|
||||
usb_free_urb(dln2->rx_urb[i]);
|
||||
kfree(dln2->rx_buf[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void dln2_free(struct dln2_dev *dln2)
|
||||
{
|
||||
dln2_free_rx_urbs(dln2);
|
||||
usb_put_dev(dln2->usb_dev);
|
||||
kfree(dln2);
|
||||
}
|
||||
|
||||
static int dln2_setup_rx_urbs(struct dln2_dev *dln2,
|
||||
struct usb_host_interface *hostif)
|
||||
{
|
||||
int i;
|
||||
int ret;
|
||||
const int rx_max_size = DLN2_RX_BUF_SIZE;
|
||||
struct device *dev = &dln2->interface->dev;
|
||||
|
||||
for (i = 0; i < DLN2_MAX_URBS; i++) {
|
||||
dln2->rx_buf[i] = kmalloc(rx_max_size, GFP_KERNEL);
|
||||
if (!dln2->rx_buf[i])
|
||||
return -ENOMEM;
|
||||
|
||||
dln2->rx_urb[i] = usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (!dln2->rx_urb[i])
|
||||
return -ENOMEM;
|
||||
|
||||
usb_fill_bulk_urb(dln2->rx_urb[i], dln2->usb_dev,
|
||||
usb_rcvbulkpipe(dln2->usb_dev, dln2->ep_in),
|
||||
dln2->rx_buf[i], rx_max_size, dln2_rx, dln2);
|
||||
|
||||
ret = usb_submit_urb(dln2->rx_urb[i], GFP_KERNEL);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to submit RX URB: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct dln2_platform_data dln2_pdata_gpio = {
|
||||
.handle = DLN2_HANDLE_GPIO,
|
||||
};
|
||||
|
||||
/* Only one I2C port seems to be supported on current hardware */
|
||||
static struct dln2_platform_data dln2_pdata_i2c = {
|
||||
.handle = DLN2_HANDLE_I2C,
|
||||
.port = 0,
|
||||
};
|
||||
|
||||
/* Only one SPI port supported */
|
||||
static struct dln2_platform_data dln2_pdata_spi = {
|
||||
.handle = DLN2_HANDLE_SPI,
|
||||
.port = 0,
|
||||
};
|
||||
|
||||
static const struct mfd_cell dln2_devs[] = {
|
||||
{
|
||||
.name = "dln2-gpio",
|
||||
.platform_data = &dln2_pdata_gpio,
|
||||
.pdata_size = sizeof(struct dln2_platform_data),
|
||||
},
|
||||
{
|
||||
.name = "dln2-i2c",
|
||||
.platform_data = &dln2_pdata_i2c,
|
||||
.pdata_size = sizeof(struct dln2_platform_data),
|
||||
},
|
||||
{
|
||||
.name = "dln2-spi",
|
||||
.platform_data = &dln2_pdata_spi,
|
||||
.pdata_size = sizeof(struct dln2_platform_data),
|
||||
},
|
||||
};
|
||||
|
||||
static void dln2_disconnect(struct usb_interface *interface)
|
||||
{
|
||||
struct dln2_dev *dln2 = usb_get_intfdata(interface);
|
||||
int i, j;
|
||||
|
||||
/* don't allow starting new transfers */
|
||||
spin_lock(&dln2->disconnect_lock);
|
||||
dln2->disconnect = true;
|
||||
spin_unlock(&dln2->disconnect_lock);
|
||||
|
||||
/* cancel in progress transfers */
|
||||
for (i = 0; i < DLN2_HANDLES; i++) {
|
||||
struct dln2_mod_rx_slots *rxs = &dln2->mod_rx_slots[i];
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&rxs->lock, flags);
|
||||
|
||||
/* cancel all response waiters */
|
||||
for (j = 0; j < DLN2_MAX_RX_SLOTS; j++) {
|
||||
struct dln2_rx_context *rxc = &rxs->slots[j];
|
||||
|
||||
if (rxc->in_use)
|
||||
complete(&rxc->done);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&rxs->lock, flags);
|
||||
}
|
||||
|
||||
/* wait for transfers to end */
|
||||
wait_event(dln2->disconnect_wq, !dln2->active_transfers);
|
||||
|
||||
mfd_remove_devices(&interface->dev);
|
||||
|
||||
dln2_free(dln2);
|
||||
}
|
||||
|
||||
static int dln2_probe(struct usb_interface *interface,
|
||||
const struct usb_device_id *usb_id)
|
||||
{
|
||||
struct usb_host_interface *hostif = interface->cur_altsetting;
|
||||
struct device *dev = &interface->dev;
|
||||
struct dln2_dev *dln2;
|
||||
int ret;
|
||||
int i, j;
|
||||
|
||||
if (hostif->desc.bInterfaceNumber != 0 ||
|
||||
hostif->desc.bNumEndpoints < 2)
|
||||
return -ENODEV;
|
||||
|
||||
dln2 = kzalloc(sizeof(*dln2), GFP_KERNEL);
|
||||
if (!dln2)
|
||||
return -ENOMEM;
|
||||
|
||||
dln2->ep_out = hostif->endpoint[0].desc.bEndpointAddress;
|
||||
dln2->ep_in = hostif->endpoint[1].desc.bEndpointAddress;
|
||||
dln2->usb_dev = usb_get_dev(interface_to_usbdev(interface));
|
||||
dln2->interface = interface;
|
||||
usb_set_intfdata(interface, dln2);
|
||||
init_waitqueue_head(&dln2->disconnect_wq);
|
||||
|
||||
for (i = 0; i < DLN2_HANDLES; i++) {
|
||||
init_waitqueue_head(&dln2->mod_rx_slots[i].wq);
|
||||
spin_lock_init(&dln2->mod_rx_slots[i].lock);
|
||||
for (j = 0; j < DLN2_MAX_RX_SLOTS; j++)
|
||||
init_completion(&dln2->mod_rx_slots[i].slots[j].done);
|
||||
}
|
||||
|
||||
spin_lock_init(&dln2->event_cb_lock);
|
||||
spin_lock_init(&dln2->disconnect_lock);
|
||||
INIT_LIST_HEAD(&dln2->event_cb_list);
|
||||
|
||||
ret = dln2_setup_rx_urbs(dln2, hostif);
|
||||
if (ret)
|
||||
goto out_cleanup;
|
||||
|
||||
ret = dln2_hw_init(dln2);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to initialize hardware\n");
|
||||
goto out_cleanup;
|
||||
}
|
||||
|
||||
ret = mfd_add_hotplug_devices(dev, dln2_devs, ARRAY_SIZE(dln2_devs));
|
||||
if (ret != 0) {
|
||||
dev_err(dev, "failed to add mfd devices to core\n");
|
||||
goto out_cleanup;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
out_cleanup:
|
||||
dln2_free(dln2);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct usb_device_id dln2_table[] = {
|
||||
{ USB_DEVICE(0xa257, 0x2013) },
|
||||
{ }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(usb, dln2_table);
|
||||
|
||||
static struct usb_driver dln2_driver = {
|
||||
.name = "dln2",
|
||||
.probe = dln2_probe,
|
||||
.disconnect = dln2_disconnect,
|
||||
.id_table = dln2_table,
|
||||
};
|
||||
|
||||
module_usb_driver(dln2_driver);
|
||||
|
||||
MODULE_AUTHOR("Octavian Purdila <octavian.purdila@intel.com>");
|
||||
MODULE_DESCRIPTION("Core driver for the Diolan DLN2 interface adapter");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -193,11 +193,7 @@ static int lpc_sch_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = mfd_add_devices(&dev->dev, 0, lpc_sch_cells, cells, NULL, 0, NULL);
|
||||
if (ret)
|
||||
mfd_remove_devices(&dev->dev);
|
||||
|
||||
return ret;
|
||||
return mfd_add_devices(&dev->dev, 0, lpc_sch_cells, cells, NULL, 0, NULL);
|
||||
}
|
||||
|
||||
static void lpc_sch_remove(struct pci_dev *dev)
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* max14577.c - mfd core driver for the Maxim 14577/77836
|
||||
*
|
||||
* Copyright (C) 2014 Samsung Electrnoics
|
||||
* Copyright (C) 2014 Samsung Electronics
|
||||
* Chanwoo Choi <cw00.choi@samsung.com>
|
||||
* Krzysztof Kozlowski <k.kozlowski@samsung.com>
|
||||
*
|
||||
|
@ -43,9 +43,15 @@
|
||||
|
||||
static const struct mfd_cell max77693_devs[] = {
|
||||
{ .name = "max77693-pmic", },
|
||||
{ .name = "max77693-charger", },
|
||||
{
|
||||
.name = "max77693-charger",
|
||||
.of_compatible = "maxim,max77693-charger",
|
||||
},
|
||||
{ .name = "max77693-muic", },
|
||||
{ .name = "max77693-haptic", },
|
||||
{
|
||||
.name = "max77693-haptic",
|
||||
.of_compatible = "maxim,max77693-haptic",
|
||||
},
|
||||
{
|
||||
.name = "max77693-flash",
|
||||
.of_compatible = "maxim,max77693-flash",
|
||||
@ -147,6 +153,12 @@ static const struct regmap_irq_chip max77693_muic_irq_chip = {
|
||||
.num_irqs = ARRAY_SIZE(max77693_muic_irqs),
|
||||
};
|
||||
|
||||
static const struct regmap_config max77693_regmap_haptic_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.max_register = MAX77693_HAPTIC_REG_END,
|
||||
};
|
||||
|
||||
static int max77693_i2c_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
@ -196,6 +208,15 @@ static int max77693_i2c_probe(struct i2c_client *i2c,
|
||||
}
|
||||
i2c_set_clientdata(max77693->haptic, max77693);
|
||||
|
||||
max77693->regmap_haptic = devm_regmap_init_i2c(max77693->haptic,
|
||||
&max77693_regmap_haptic_config);
|
||||
if (IS_ERR(max77693->regmap_haptic)) {
|
||||
ret = PTR_ERR(max77693->regmap_haptic);
|
||||
dev_err(max77693->dev,
|
||||
"failed to initialize haptic register map: %d\n", ret);
|
||||
goto err_regmap;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize register map for MUIC device because use regmap-muic
|
||||
* instance of MUIC device when irq of max77693 is initialized
|
||||
@ -207,7 +228,7 @@ static int max77693_i2c_probe(struct i2c_client *i2c,
|
||||
ret = PTR_ERR(max77693->regmap_muic);
|
||||
dev_err(max77693->dev,
|
||||
"failed to allocate register map: %d\n", ret);
|
||||
goto err_regmap_muic;
|
||||
goto err_regmap;
|
||||
}
|
||||
|
||||
ret = regmap_add_irq_chip(max77693->regmap, max77693->irq,
|
||||
@ -217,7 +238,7 @@ static int max77693_i2c_probe(struct i2c_client *i2c,
|
||||
&max77693->irq_data_led);
|
||||
if (ret) {
|
||||
dev_err(max77693->dev, "failed to add irq chip: %d\n", ret);
|
||||
goto err_regmap_muic;
|
||||
goto err_regmap;
|
||||
}
|
||||
|
||||
ret = regmap_add_irq_chip(max77693->regmap, max77693->irq,
|
||||
@ -280,7 +301,7 @@ static int max77693_i2c_probe(struct i2c_client *i2c,
|
||||
regmap_del_irq_chip(max77693->irq, max77693->irq_data_topsys);
|
||||
err_irq_topsys:
|
||||
regmap_del_irq_chip(max77693->irq, max77693->irq_data_led);
|
||||
err_regmap_muic:
|
||||
err_regmap:
|
||||
i2c_unregister_device(max77693->haptic);
|
||||
err_i2c_haptic:
|
||||
i2c_unregister_device(max77693->muic);
|
||||
|
@ -125,9 +125,15 @@ static int mfd_add_device(struct device *parent, int id,
|
||||
struct platform_device *pdev;
|
||||
struct device_node *np = NULL;
|
||||
int ret = -ENOMEM;
|
||||
int platform_id;
|
||||
int r;
|
||||
|
||||
pdev = platform_device_alloc(cell->name, id + cell->id);
|
||||
if (id < 0)
|
||||
platform_id = id;
|
||||
else
|
||||
platform_id = id + cell->id;
|
||||
|
||||
pdev = platform_device_alloc(cell->name, platform_id);
|
||||
if (!pdev)
|
||||
goto fail_alloc;
|
||||
|
||||
|
@ -130,6 +130,12 @@ static int rts5227_extra_init_hw(struct rtsx_pcr *pcr)
|
||||
|
||||
static int rts5227_optimize_phy(struct rtsx_pcr *pcr)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = rtsx_gops_pm_reset(pcr);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* Optimize RX sensitivity */
|
||||
return rtsx_pci_write_phy_register(pcr, 0x00, 0xBA42);
|
||||
}
|
||||
|
@ -130,6 +130,10 @@ static int rts5249_optimize_phy(struct rtsx_pcr *pcr)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = rtsx_gops_pm_reset(pcr);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = rtsx_pci_write_phy_register(pcr, PHY_REG_REV,
|
||||
PHY_REG_REV_RESV | PHY_REG_REV_RXIDLE_LATCHED |
|
||||
PHY_REG_REV_P1_EN | PHY_REG_REV_RXIDLE_EN |
|
||||
|
37
drivers/mfd/rtsx_gops.c
Normal file
37
drivers/mfd/rtsx_gops.c
Normal file
@ -0,0 +1,37 @@
|
||||
/* Driver for Realtek PCI-Express card reader
|
||||
*
|
||||
* Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.
|
||||
*
|
||||
* 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; either version 2, or (at your option) any
|
||||
* later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* 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; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Author:
|
||||
* Micky Ching <micky_ching@realsil.com.cn>
|
||||
*/
|
||||
|
||||
#include <linux/mfd/rtsx_pci.h>
|
||||
#include "rtsx_pcr.h"
|
||||
|
||||
int rtsx_gops_pm_reset(struct rtsx_pcr *pcr)
|
||||
{
|
||||
int err;
|
||||
|
||||
/* init aspm */
|
||||
rtsx_pci_write_register(pcr, ASPM_FORCE_CTL, 0xFF, 0x00);
|
||||
err = rtsx_pci_update_cfg_byte(pcr, LCTLR, ~LCTLR_ASPM_CTL_MASK, 0x00);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* reset PM_CTRL3 before send buffer cmd */
|
||||
return rtsx_pci_write_register(pcr, PM_CTRL3, D3_DELINK_MODE_EN, 0x00);
|
||||
}
|
@ -72,4 +72,7 @@ do { \
|
||||
pcr->ms_pull_ctl_disable_tbl = __device##_ms_pull_ctl_disable_tbl; \
|
||||
} while (0)
|
||||
|
||||
/* generic operations */
|
||||
int rtsx_gops_pm_reset(struct rtsx_pcr *pcr);
|
||||
|
||||
#endif
|
||||
|
@ -647,8 +647,8 @@ static int rtsx_usb_probe(struct usb_interface *intf,
|
||||
/* initialize USB SG transfer timer */
|
||||
setup_timer(&ucr->sg_timer, rtsx_usb_sg_timed_out, (unsigned long) ucr);
|
||||
|
||||
ret = mfd_add_devices(&intf->dev, usb_dev->devnum, rtsx_usb_cells,
|
||||
ARRAY_SIZE(rtsx_usb_cells), NULL, 0, NULL);
|
||||
ret = mfd_add_hotplug_devices(&intf->dev, rtsx_usb_cells,
|
||||
ARRAY_SIZE(rtsx_usb_cells));
|
||||
if (ret)
|
||||
goto out_init_fail;
|
||||
|
||||
|
@ -27,11 +27,11 @@
|
||||
#include <linux/mfd/samsung/irq.h>
|
||||
#include <linux/mfd/samsung/s2mpa01.h>
|
||||
#include <linux/mfd/samsung/s2mps11.h>
|
||||
#include <linux/mfd/samsung/s2mps13.h>
|
||||
#include <linux/mfd/samsung/s2mps14.h>
|
||||
#include <linux/mfd/samsung/s2mpu02.h>
|
||||
#include <linux/mfd/samsung/s5m8763.h>
|
||||
#include <linux/mfd/samsung/s5m8767.h>
|
||||
#include <linux/regulator/machine.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
static const struct mfd_cell s5m8751_devs[] = {
|
||||
@ -74,6 +74,15 @@ static const struct mfd_cell s2mps11_devs[] = {
|
||||
}
|
||||
};
|
||||
|
||||
static const struct mfd_cell s2mps13_devs[] = {
|
||||
{ .name = "s2mps13-pmic", },
|
||||
{ .name = "s2mps13-rtc", },
|
||||
{
|
||||
.name = "s2mps13-clk",
|
||||
.of_compatible = "samsung,s2mps13-clk",
|
||||
},
|
||||
};
|
||||
|
||||
static const struct mfd_cell s2mps14_devs[] = {
|
||||
{
|
||||
.name = "s2mps14-pmic",
|
||||
@ -107,6 +116,9 @@ static const struct of_device_id sec_dt_match[] = {
|
||||
}, {
|
||||
.compatible = "samsung,s2mps11-pmic",
|
||||
.data = (void *)S2MPS11X,
|
||||
}, {
|
||||
.compatible = "samsung,s2mps13-pmic",
|
||||
.data = (void *)S2MPS13X,
|
||||
}, {
|
||||
.compatible = "samsung,s2mps14-pmic",
|
||||
.data = (void *)S2MPS14X,
|
||||
@ -194,6 +206,15 @@ static const struct regmap_config s2mps11_regmap_config = {
|
||||
.cache_type = REGCACHE_FLAT,
|
||||
};
|
||||
|
||||
static const struct regmap_config s2mps13_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
|
||||
.max_register = S2MPS13_REG_LDODSCH5,
|
||||
.volatile_reg = s2mps11_volatile,
|
||||
.cache_type = REGCACHE_FLAT,
|
||||
};
|
||||
|
||||
static const struct regmap_config s2mps14_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
@ -325,6 +346,9 @@ static int sec_pmic_probe(struct i2c_client *i2c,
|
||||
case S2MPS11X:
|
||||
regmap = &s2mps11_regmap_config;
|
||||
break;
|
||||
case S2MPS13X:
|
||||
regmap = &s2mps13_regmap_config;
|
||||
break;
|
||||
case S2MPS14X:
|
||||
regmap = &s2mps14_regmap_config;
|
||||
break;
|
||||
@ -378,6 +402,10 @@ static int sec_pmic_probe(struct i2c_client *i2c,
|
||||
sec_devs = s2mps11_devs;
|
||||
num_sec_devs = ARRAY_SIZE(s2mps11_devs);
|
||||
break;
|
||||
case S2MPS13X:
|
||||
sec_devs = s2mps13_devs;
|
||||
num_sec_devs = ARRAY_SIZE(s2mps13_devs);
|
||||
break;
|
||||
case S2MPS14X:
|
||||
sec_devs = s2mps14_devs;
|
||||
num_sec_devs = ARRAY_SIZE(s2mps14_devs);
|
||||
@ -432,15 +460,6 @@ static int sec_pmic_suspend(struct device *dev)
|
||||
*/
|
||||
disable_irq(sec_pmic->irq);
|
||||
|
||||
switch (sec_pmic->device_type) {
|
||||
case S2MPS14X:
|
||||
case S2MPU02:
|
||||
regulator_suspend_prepare(PM_SUSPEND_MEM);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -389,14 +389,22 @@ static const struct regmap_irq_chip s2mps11_irq_chip = {
|
||||
.ack_base = S2MPS11_REG_INT1,
|
||||
};
|
||||
|
||||
#define S2MPS1X_IRQ_CHIP_COMMON_DATA \
|
||||
.irqs = s2mps14_irqs, \
|
||||
.num_irqs = ARRAY_SIZE(s2mps14_irqs), \
|
||||
.num_regs = 3, \
|
||||
.status_base = S2MPS14_REG_INT1, \
|
||||
.mask_base = S2MPS14_REG_INT1M, \
|
||||
.ack_base = S2MPS14_REG_INT1 \
|
||||
|
||||
static const struct regmap_irq_chip s2mps13_irq_chip = {
|
||||
.name = "s2mps13",
|
||||
S2MPS1X_IRQ_CHIP_COMMON_DATA,
|
||||
};
|
||||
|
||||
static const struct regmap_irq_chip s2mps14_irq_chip = {
|
||||
.name = "s2mps14",
|
||||
.irqs = s2mps14_irqs,
|
||||
.num_irqs = ARRAY_SIZE(s2mps14_irqs),
|
||||
.num_regs = 3,
|
||||
.status_base = S2MPS14_REG_INT1,
|
||||
.mask_base = S2MPS14_REG_INT1M,
|
||||
.ack_base = S2MPS14_REG_INT1,
|
||||
S2MPS1X_IRQ_CHIP_COMMON_DATA,
|
||||
};
|
||||
|
||||
static const struct regmap_irq_chip s2mpu02_irq_chip = {
|
||||
@ -452,6 +460,9 @@ int sec_irq_init(struct sec_pmic_dev *sec_pmic)
|
||||
case S2MPS11X:
|
||||
sec_irq_chip = &s2mps11_irq_chip;
|
||||
break;
|
||||
case S2MPS13X:
|
||||
sec_irq_chip = &s2mps13_irq_chip;
|
||||
break;
|
||||
case S2MPS14X:
|
||||
sec_irq_chip = &s2mps14_irq_chip;
|
||||
break;
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_platform.h>
|
||||
@ -22,31 +23,94 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
static struct platform_driver syscon_driver;
|
||||
|
||||
static DEFINE_SPINLOCK(syscon_list_slock);
|
||||
static LIST_HEAD(syscon_list);
|
||||
|
||||
struct syscon {
|
||||
struct device_node *np;
|
||||
struct regmap *regmap;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
static int syscon_match_node(struct device *dev, void *data)
|
||||
{
|
||||
struct device_node *dn = data;
|
||||
static struct regmap_config syscon_regmap_config = {
|
||||
.reg_bits = 32,
|
||||
.val_bits = 32,
|
||||
.reg_stride = 4,
|
||||
};
|
||||
|
||||
return (dev->of_node == dn) ? 1 : 0;
|
||||
static struct syscon *of_syscon_register(struct device_node *np)
|
||||
{
|
||||
struct syscon *syscon;
|
||||
struct regmap *regmap;
|
||||
void __iomem *base;
|
||||
int ret;
|
||||
struct regmap_config syscon_config = syscon_regmap_config;
|
||||
|
||||
if (!of_device_is_compatible(np, "syscon"))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
syscon = kzalloc(sizeof(*syscon), GFP_KERNEL);
|
||||
if (!syscon)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
base = of_iomap(np, 0);
|
||||
if (!base) {
|
||||
ret = -ENOMEM;
|
||||
goto err_map;
|
||||
}
|
||||
|
||||
/* Parse the device's DT node for an endianness specification */
|
||||
if (of_property_read_bool(np, "big-endian"))
|
||||
syscon_config.val_format_endian = REGMAP_ENDIAN_BIG;
|
||||
else if (of_property_read_bool(np, "little-endian"))
|
||||
syscon_config.val_format_endian = REGMAP_ENDIAN_LITTLE;
|
||||
|
||||
regmap = regmap_init_mmio(NULL, base, &syscon_config);
|
||||
if (IS_ERR(regmap)) {
|
||||
pr_err("regmap init failed\n");
|
||||
ret = PTR_ERR(regmap);
|
||||
goto err_regmap;
|
||||
}
|
||||
|
||||
syscon->regmap = regmap;
|
||||
syscon->np = np;
|
||||
|
||||
spin_lock(&syscon_list_slock);
|
||||
list_add_tail(&syscon->list, &syscon_list);
|
||||
spin_unlock(&syscon_list_slock);
|
||||
|
||||
return syscon;
|
||||
|
||||
err_regmap:
|
||||
iounmap(base);
|
||||
err_map:
|
||||
kfree(syscon);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
struct regmap *syscon_node_to_regmap(struct device_node *np)
|
||||
{
|
||||
struct syscon *syscon;
|
||||
struct device *dev;
|
||||
struct syscon *entry, *syscon = NULL;
|
||||
|
||||
dev = driver_find_device(&syscon_driver.driver, NULL, np,
|
||||
syscon_match_node);
|
||||
if (!dev)
|
||||
return ERR_PTR(-EPROBE_DEFER);
|
||||
spin_lock(&syscon_list_slock);
|
||||
|
||||
syscon = dev_get_drvdata(dev);
|
||||
list_for_each_entry(entry, &syscon_list, list)
|
||||
if (entry->np == np) {
|
||||
syscon = entry;
|
||||
break;
|
||||
}
|
||||
|
||||
spin_unlock(&syscon_list_slock);
|
||||
|
||||
if (!syscon)
|
||||
syscon = of_syscon_register(np);
|
||||
|
||||
if (IS_ERR(syscon))
|
||||
return ERR_CAST(syscon);
|
||||
|
||||
return syscon->regmap;
|
||||
}
|
||||
@ -110,17 +174,6 @@ struct regmap *syscon_regmap_lookup_by_phandle(struct device_node *np,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(syscon_regmap_lookup_by_phandle);
|
||||
|
||||
static const struct of_device_id of_syscon_match[] = {
|
||||
{ .compatible = "syscon", },
|
||||
{ },
|
||||
};
|
||||
|
||||
static struct regmap_config syscon_regmap_config = {
|
||||
.reg_bits = 32,
|
||||
.val_bits = 32,
|
||||
.reg_stride = 4,
|
||||
};
|
||||
|
||||
static int syscon_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
@ -167,7 +220,6 @@ static struct platform_driver syscon_driver = {
|
||||
.driver = {
|
||||
.name = "syscon",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_syscon_match,
|
||||
},
|
||||
.probe = syscon_probe,
|
||||
.id_table = syscon_ids,
|
||||
|
@ -87,7 +87,7 @@ static int t7l66xb_mmc_enable(struct platform_device *mmc)
|
||||
unsigned long flags;
|
||||
u8 dev_ctl;
|
||||
|
||||
clk_enable(t7l66xb->clk32k);
|
||||
clk_prepare_enable(t7l66xb->clk32k);
|
||||
|
||||
spin_lock_irqsave(&t7l66xb->lock, flags);
|
||||
|
||||
@ -118,7 +118,7 @@ static int t7l66xb_mmc_disable(struct platform_device *mmc)
|
||||
|
||||
spin_unlock_irqrestore(&t7l66xb->lock, flags);
|
||||
|
||||
clk_disable(t7l66xb->clk32k);
|
||||
clk_disable_unprepare(t7l66xb->clk32k);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -285,7 +285,7 @@ static int t7l66xb_suspend(struct platform_device *dev, pm_message_t state)
|
||||
|
||||
if (pdata && pdata->suspend)
|
||||
pdata->suspend(dev);
|
||||
clk_disable(t7l66xb->clk48m);
|
||||
clk_disable_unprepare(t7l66xb->clk48m);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -295,7 +295,7 @@ static int t7l66xb_resume(struct platform_device *dev)
|
||||
struct t7l66xb *t7l66xb = platform_get_drvdata(dev);
|
||||
struct t7l66xb_platform_data *pdata = dev_get_platdata(&dev->dev);
|
||||
|
||||
clk_enable(t7l66xb->clk48m);
|
||||
clk_prepare_enable(t7l66xb->clk48m);
|
||||
if (pdata && pdata->resume)
|
||||
pdata->resume(dev);
|
||||
|
||||
@ -369,7 +369,7 @@ static int t7l66xb_probe(struct platform_device *dev)
|
||||
goto err_ioremap;
|
||||
}
|
||||
|
||||
clk_enable(t7l66xb->clk48m);
|
||||
clk_prepare_enable(t7l66xb->clk48m);
|
||||
|
||||
if (pdata && pdata->enable)
|
||||
pdata->enable(dev);
|
||||
@ -414,9 +414,9 @@ static int t7l66xb_remove(struct platform_device *dev)
|
||||
int ret;
|
||||
|
||||
ret = pdata->disable(dev);
|
||||
clk_disable(t7l66xb->clk48m);
|
||||
clk_disable_unprepare(t7l66xb->clk48m);
|
||||
clk_put(t7l66xb->clk48m);
|
||||
clk_disable(t7l66xb->clk32k);
|
||||
clk_disable_unprepare(t7l66xb->clk32k);
|
||||
clk_put(t7l66xb->clk32k);
|
||||
t7l66xb_detach_irq(dev);
|
||||
iounmap(t7l66xb->scr);
|
||||
|
@ -241,10 +241,8 @@ static struct irq_domain_ops tc3589x_irq_ops = {
|
||||
|
||||
static int tc3589x_irq_init(struct tc3589x *tc3589x, struct device_node *np)
|
||||
{
|
||||
int base = tc3589x->irq_base;
|
||||
|
||||
tc3589x->domain = irq_domain_add_simple(
|
||||
np, TC3589x_NR_INTERNAL_IRQS, base,
|
||||
np, TC3589x_NR_INTERNAL_IRQS, 0,
|
||||
&tc3589x_irq_ops, tc3589x);
|
||||
|
||||
if (!tc3589x->domain) {
|
||||
@ -298,7 +296,7 @@ static int tc3589x_device_init(struct tc3589x *tc3589x)
|
||||
if (blocks & TC3589x_BLOCK_GPIO) {
|
||||
ret = mfd_add_devices(tc3589x->dev, -1, tc3589x_dev_gpio,
|
||||
ARRAY_SIZE(tc3589x_dev_gpio), NULL,
|
||||
tc3589x->irq_base, tc3589x->domain);
|
||||
0, tc3589x->domain);
|
||||
if (ret) {
|
||||
dev_err(tc3589x->dev, "failed to add gpio child\n");
|
||||
return ret;
|
||||
@ -309,7 +307,7 @@ static int tc3589x_device_init(struct tc3589x *tc3589x)
|
||||
if (blocks & TC3589x_BLOCK_KEYPAD) {
|
||||
ret = mfd_add_devices(tc3589x->dev, -1, tc3589x_dev_keypad,
|
||||
ARRAY_SIZE(tc3589x_dev_keypad), NULL,
|
||||
tc3589x->irq_base, tc3589x->domain);
|
||||
0, tc3589x->domain);
|
||||
if (ret) {
|
||||
dev_err(tc3589x->dev, "failed to keypad child\n");
|
||||
return ret;
|
||||
@ -404,7 +402,6 @@ static int tc3589x_probe(struct i2c_client *i2c,
|
||||
tc3589x->dev = &i2c->dev;
|
||||
tc3589x->i2c = i2c;
|
||||
tc3589x->pdata = pdata;
|
||||
tc3589x->irq_base = pdata->irq_base;
|
||||
|
||||
switch (version) {
|
||||
case TC3589X_TC35893:
|
||||
|
@ -52,7 +52,7 @@ static int tc6387xb_suspend(struct platform_device *dev, pm_message_t state)
|
||||
|
||||
if (pdata && pdata->suspend)
|
||||
pdata->suspend(dev);
|
||||
clk_disable(tc6387xb->clk32k);
|
||||
clk_disable_unprepare(tc6387xb->clk32k);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -62,7 +62,7 @@ static int tc6387xb_resume(struct platform_device *dev)
|
||||
struct tc6387xb *tc6387xb = platform_get_drvdata(dev);
|
||||
struct tc6387xb_platform_data *pdata = dev_get_platdata(&dev->dev);
|
||||
|
||||
clk_enable(tc6387xb->clk32k);
|
||||
clk_prepare_enable(tc6387xb->clk32k);
|
||||
if (pdata && pdata->resume)
|
||||
pdata->resume(dev);
|
||||
|
||||
@ -100,7 +100,7 @@ static int tc6387xb_mmc_enable(struct platform_device *mmc)
|
||||
struct platform_device *dev = to_platform_device(mmc->dev.parent);
|
||||
struct tc6387xb *tc6387xb = platform_get_drvdata(dev);
|
||||
|
||||
clk_enable(tc6387xb->clk32k);
|
||||
clk_prepare_enable(tc6387xb->clk32k);
|
||||
|
||||
tmio_core_mmc_enable(tc6387xb->scr + 0x200, 0,
|
||||
tc6387xb_mmc_resources[0].start & 0xfffe);
|
||||
@ -113,7 +113,7 @@ static int tc6387xb_mmc_disable(struct platform_device *mmc)
|
||||
struct platform_device *dev = to_platform_device(mmc->dev.parent);
|
||||
struct tc6387xb *tc6387xb = platform_get_drvdata(dev);
|
||||
|
||||
clk_disable(tc6387xb->clk32k);
|
||||
clk_disable_unprepare(tc6387xb->clk32k);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -214,7 +214,7 @@ static int tc6387xb_remove(struct platform_device *dev)
|
||||
mfd_remove_devices(&dev->dev);
|
||||
iounmap(tc6387xb->scr);
|
||||
release_resource(&tc6387xb->rscr);
|
||||
clk_disable(tc6387xb->clk32k);
|
||||
clk_disable_unprepare(tc6387xb->clk32k);
|
||||
clk_put(tc6387xb->clk32k);
|
||||
kfree(tc6387xb);
|
||||
|
||||
|
@ -263,6 +263,17 @@ static int tc6393xb_ohci_disable(struct platform_device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tc6393xb_ohci_suspend(struct platform_device *dev)
|
||||
{
|
||||
struct tc6393xb_platform_data *tcpd = dev_get_platdata(dev->dev.parent);
|
||||
|
||||
/* We can't properly store/restore OHCI state, so fail here */
|
||||
if (tcpd->resume_restore)
|
||||
return -EBUSY;
|
||||
|
||||
return tc6393xb_ohci_disable(dev);
|
||||
}
|
||||
|
||||
static int tc6393xb_fb_enable(struct platform_device *dev)
|
||||
{
|
||||
struct tc6393xb *tc6393xb = dev_get_drvdata(dev->dev.parent);
|
||||
@ -403,7 +414,7 @@ static struct mfd_cell tc6393xb_cells[] = {
|
||||
.num_resources = ARRAY_SIZE(tc6393xb_ohci_resources),
|
||||
.resources = tc6393xb_ohci_resources,
|
||||
.enable = tc6393xb_ohci_enable,
|
||||
.suspend = tc6393xb_ohci_disable,
|
||||
.suspend = tc6393xb_ohci_suspend,
|
||||
.resume = tc6393xb_ohci_enable,
|
||||
.disable = tc6393xb_ohci_disable,
|
||||
},
|
||||
@ -654,7 +665,7 @@ static int tc6393xb_probe(struct platform_device *dev)
|
||||
goto err_ioremap;
|
||||
}
|
||||
|
||||
ret = clk_enable(tc6393xb->clk);
|
||||
ret = clk_prepare_enable(tc6393xb->clk);
|
||||
if (ret)
|
||||
goto err_clk_enable;
|
||||
|
||||
@ -717,7 +728,7 @@ static int tc6393xb_probe(struct platform_device *dev)
|
||||
gpiochip_remove(&tc6393xb->gpio);
|
||||
tcpd->disable(dev);
|
||||
err_enable:
|
||||
clk_disable(tc6393xb->clk);
|
||||
clk_disable_unprepare(tc6393xb->clk);
|
||||
err_clk_enable:
|
||||
iounmap(tc6393xb->scr);
|
||||
err_ioremap:
|
||||
@ -748,7 +759,7 @@ static int tc6393xb_remove(struct platform_device *dev)
|
||||
gpiochip_remove(&tc6393xb->gpio);
|
||||
|
||||
ret = tcpd->disable(dev);
|
||||
clk_disable(tc6393xb->clk);
|
||||
clk_disable_unprepare(tc6393xb->clk);
|
||||
iounmap(tc6393xb->scr);
|
||||
release_resource(&tc6393xb->rscr);
|
||||
clk_put(tc6393xb->clk);
|
||||
@ -776,7 +787,7 @@ static int tc6393xb_suspend(struct platform_device *dev, pm_message_t state)
|
||||
ioread8(tc6393xb->scr + SCR_GPI_BCR(i));
|
||||
}
|
||||
ret = tcpd->suspend(dev);
|
||||
clk_disable(tc6393xb->clk);
|
||||
clk_disable_unprepare(tc6393xb->clk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -788,7 +799,7 @@ static int tc6393xb_resume(struct platform_device *dev)
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
clk_enable(tc6393xb->clk);
|
||||
clk_prepare_enable(tc6393xb->clk);
|
||||
|
||||
ret = tcpd->resume(dev);
|
||||
if (ret)
|
||||
|
@ -76,58 +76,58 @@ static struct mfd_cell tps65090s[] = {
|
||||
static const struct regmap_irq tps65090_irqs[] = {
|
||||
/* INT1 IRQs*/
|
||||
[TPS65090_IRQ_VAC_STATUS_CHANGE] = {
|
||||
.mask = TPS65090_INT1_MASK_VAC_STATUS_CHANGE,
|
||||
.mask = TPS65090_INT1_MASK_VAC_STATUS_CHANGE,
|
||||
},
|
||||
[TPS65090_IRQ_VSYS_STATUS_CHANGE] = {
|
||||
.mask = TPS65090_INT1_MASK_VSYS_STATUS_CHANGE,
|
||||
.mask = TPS65090_INT1_MASK_VSYS_STATUS_CHANGE,
|
||||
},
|
||||
[TPS65090_IRQ_BAT_STATUS_CHANGE] = {
|
||||
.mask = TPS65090_INT1_MASK_BAT_STATUS_CHANGE,
|
||||
.mask = TPS65090_INT1_MASK_BAT_STATUS_CHANGE,
|
||||
},
|
||||
[TPS65090_IRQ_CHARGING_STATUS_CHANGE] = {
|
||||
.mask = TPS65090_INT1_MASK_CHARGING_STATUS_CHANGE,
|
||||
.mask = TPS65090_INT1_MASK_CHARGING_STATUS_CHANGE,
|
||||
},
|
||||
[TPS65090_IRQ_CHARGING_COMPLETE] = {
|
||||
.mask = TPS65090_INT1_MASK_CHARGING_COMPLETE,
|
||||
.mask = TPS65090_INT1_MASK_CHARGING_COMPLETE,
|
||||
},
|
||||
[TPS65090_IRQ_OVERLOAD_DCDC1] = {
|
||||
.mask = TPS65090_INT1_MASK_OVERLOAD_DCDC1,
|
||||
.mask = TPS65090_INT1_MASK_OVERLOAD_DCDC1,
|
||||
},
|
||||
[TPS65090_IRQ_OVERLOAD_DCDC2] = {
|
||||
.mask = TPS65090_INT1_MASK_OVERLOAD_DCDC2,
|
||||
.mask = TPS65090_INT1_MASK_OVERLOAD_DCDC2,
|
||||
},
|
||||
/* INT2 IRQs*/
|
||||
[TPS65090_IRQ_OVERLOAD_DCDC3] = {
|
||||
.reg_offset = 1,
|
||||
.mask = TPS65090_INT2_MASK_OVERLOAD_DCDC3,
|
||||
.reg_offset = 1,
|
||||
.mask = TPS65090_INT2_MASK_OVERLOAD_DCDC3,
|
||||
},
|
||||
[TPS65090_IRQ_OVERLOAD_FET1] = {
|
||||
.reg_offset = 1,
|
||||
.mask = TPS65090_INT2_MASK_OVERLOAD_FET1,
|
||||
.reg_offset = 1,
|
||||
.mask = TPS65090_INT2_MASK_OVERLOAD_FET1,
|
||||
},
|
||||
[TPS65090_IRQ_OVERLOAD_FET2] = {
|
||||
.reg_offset = 1,
|
||||
.mask = TPS65090_INT2_MASK_OVERLOAD_FET2,
|
||||
.reg_offset = 1,
|
||||
.mask = TPS65090_INT2_MASK_OVERLOAD_FET2,
|
||||
},
|
||||
[TPS65090_IRQ_OVERLOAD_FET3] = {
|
||||
.reg_offset = 1,
|
||||
.mask = TPS65090_INT2_MASK_OVERLOAD_FET3,
|
||||
.reg_offset = 1,
|
||||
.mask = TPS65090_INT2_MASK_OVERLOAD_FET3,
|
||||
},
|
||||
[TPS65090_IRQ_OVERLOAD_FET4] = {
|
||||
.reg_offset = 1,
|
||||
.mask = TPS65090_INT2_MASK_OVERLOAD_FET4,
|
||||
.reg_offset = 1,
|
||||
.mask = TPS65090_INT2_MASK_OVERLOAD_FET4,
|
||||
},
|
||||
[TPS65090_IRQ_OVERLOAD_FET5] = {
|
||||
.reg_offset = 1,
|
||||
.mask = TPS65090_INT2_MASK_OVERLOAD_FET5,
|
||||
.reg_offset = 1,
|
||||
.mask = TPS65090_INT2_MASK_OVERLOAD_FET5,
|
||||
},
|
||||
[TPS65090_IRQ_OVERLOAD_FET6] = {
|
||||
.reg_offset = 1,
|
||||
.mask = TPS65090_INT2_MASK_OVERLOAD_FET6,
|
||||
.reg_offset = 1,
|
||||
.mask = TPS65090_INT2_MASK_OVERLOAD_FET6,
|
||||
},
|
||||
[TPS65090_IRQ_OVERLOAD_FET7] = {
|
||||
.reg_offset = 1,
|
||||
.mask = TPS65090_INT2_MASK_OVERLOAD_FET7,
|
||||
.reg_offset = 1,
|
||||
.mask = TPS65090_INT2_MASK_OVERLOAD_FET7,
|
||||
},
|
||||
};
|
||||
|
||||
@ -176,7 +176,7 @@ MODULE_DEVICE_TABLE(of, tps65090_of_match);
|
||||
#endif
|
||||
|
||||
static int tps65090_i2c_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct tps65090_platform_data *pdata = dev_get_platdata(&client->dev);
|
||||
int irq_base = 0;
|
||||
@ -210,11 +210,11 @@ static int tps65090_i2c_probe(struct i2c_client *client,
|
||||
|
||||
if (client->irq) {
|
||||
ret = regmap_add_irq_chip(tps65090->rmap, client->irq,
|
||||
IRQF_ONESHOT | IRQF_TRIGGER_LOW, irq_base,
|
||||
&tps65090_irq_chip, &tps65090->irq_data);
|
||||
if (ret) {
|
||||
dev_err(&client->dev,
|
||||
"IRQ init failed with err: %d\n", ret);
|
||||
IRQF_ONESHOT | IRQF_TRIGGER_LOW, irq_base,
|
||||
&tps65090_irq_chip, &tps65090->irq_data);
|
||||
if (ret) {
|
||||
dev_err(&client->dev,
|
||||
"IRQ init failed with err: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
@ -223,8 +223,8 @@ static int tps65090_i2c_probe(struct i2c_client *client,
|
||||
}
|
||||
|
||||
ret = mfd_add_devices(tps65090->dev, -1, tps65090s,
|
||||
ARRAY_SIZE(tps65090s), NULL,
|
||||
0, regmap_irq_get_domain(tps65090->irq_data));
|
||||
ARRAY_SIZE(tps65090s), NULL,
|
||||
0, regmap_irq_get_domain(tps65090->irq_data));
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "add mfd devices failed with err: %d\n",
|
||||
ret);
|
||||
|
@ -33,9 +33,11 @@
|
||||
static const struct mfd_cell tps65217s[] = {
|
||||
{
|
||||
.name = "tps65217-pmic",
|
||||
.of_compatible = "ti,tps65217-pmic",
|
||||
},
|
||||
{
|
||||
.name = "tps65217-bl",
|
||||
.of_compatible = "ti,tps65217-bl",
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -830,6 +830,9 @@ static struct twl4030_power_data osc_off_idle = {
|
||||
};
|
||||
|
||||
static struct of_device_id twl4030_power_of_match[] = {
|
||||
{
|
||||
.compatible = "ti,twl4030-power",
|
||||
},
|
||||
{
|
||||
.compatible = "ti,twl4030-power-reset",
|
||||
.data = &omap3_reset,
|
||||
|
@ -93,9 +93,8 @@ static int vprbrd_probe(struct usb_interface *interface,
|
||||
version >> 8, version & 0xff,
|
||||
vb->usb_dev->bus->busnum, vb->usb_dev->devnum);
|
||||
|
||||
ret = mfd_add_devices(&interface->dev, PLATFORM_DEVID_AUTO,
|
||||
vprbrd_devs, ARRAY_SIZE(vprbrd_devs), NULL, 0,
|
||||
NULL);
|
||||
ret = mfd_add_hotplug_devices(&interface->dev, vprbrd_devs,
|
||||
ARRAY_SIZE(vprbrd_devs));
|
||||
if (ret != 0) {
|
||||
dev_err(&interface->dev, "Failed to add mfd devices to core.");
|
||||
goto error;
|
||||
|
@ -336,8 +336,6 @@ static const struct reg_default wm5102_reg_default[] = {
|
||||
{ 0x00000218, 0x01A6 }, /* R536 - Mic Bias Ctrl 1 */
|
||||
{ 0x00000219, 0x01A6 }, /* R537 - Mic Bias Ctrl 2 */
|
||||
{ 0x0000021A, 0x01A6 }, /* R538 - Mic Bias Ctrl 3 */
|
||||
{ 0x00000225, 0x0400 }, /* R549 - HP Ctrl 1L */
|
||||
{ 0x00000226, 0x0400 }, /* R550 - HP Ctrl 1R */
|
||||
{ 0x00000293, 0x0000 }, /* R659 - Accessory Detect Mode 1 */
|
||||
{ 0x0000029B, 0x0020 }, /* R667 - Headphone Detect 1 */
|
||||
{ 0x0000029C, 0x0000 }, /* R668 - Headphone Detect 2 */
|
||||
@ -1112,6 +1110,8 @@ static bool wm5102_readable_register(struct device *dev, unsigned int reg)
|
||||
case ARIZONA_MIC_BIAS_CTRL_1:
|
||||
case ARIZONA_MIC_BIAS_CTRL_2:
|
||||
case ARIZONA_MIC_BIAS_CTRL_3:
|
||||
case ARIZONA_HP_CTRL_1L:
|
||||
case ARIZONA_HP_CTRL_1R:
|
||||
case ARIZONA_ACCESSORY_DETECT_MODE_1:
|
||||
case ARIZONA_HEADPHONE_DETECT_1:
|
||||
case ARIZONA_HEADPHONE_DETECT_2:
|
||||
@ -1949,6 +1949,8 @@ static bool wm5102_volatile_register(struct device *dev, unsigned int reg)
|
||||
case ARIZONA_DSP1_SCRATCH_1:
|
||||
case ARIZONA_DSP1_SCRATCH_2:
|
||||
case ARIZONA_DSP1_SCRATCH_3:
|
||||
case ARIZONA_HP_CTRL_1L:
|
||||
case ARIZONA_HP_CTRL_1R:
|
||||
case ARIZONA_HEADPHONE_DETECT_2:
|
||||
case ARIZONA_HP_DACVAL:
|
||||
case ARIZONA_MIC_DETECT_3:
|
||||
|
@ -895,8 +895,16 @@ static const struct reg_default wm5110_reg_default[] = {
|
||||
{ 0x00000548, 0x1818 }, /* R1352 - AIF2 Frame Ctrl 2 */
|
||||
{ 0x00000549, 0x0000 }, /* R1353 - AIF2 Frame Ctrl 3 */
|
||||
{ 0x0000054A, 0x0001 }, /* R1354 - AIF2 Frame Ctrl 4 */
|
||||
{ 0x0000054B, 0x0002 }, /* R1355 - AIF2 Frame Ctrl 5 */
|
||||
{ 0x0000054C, 0x0003 }, /* R1356 - AIF2 Frame Ctrl 6 */
|
||||
{ 0x0000054D, 0x0004 }, /* R1357 - AIF2 Frame Ctrl 7 */
|
||||
{ 0x0000054E, 0x0005 }, /* R1358 - AIF2 Frame Ctrl 8 */
|
||||
{ 0x00000551, 0x0000 }, /* R1361 - AIF2 Frame Ctrl 11 */
|
||||
{ 0x00000552, 0x0001 }, /* R1362 - AIF2 Frame Ctrl 12 */
|
||||
{ 0x00000553, 0x0002 }, /* R1363 - AIF2 Frame Ctrl 13 */
|
||||
{ 0x00000554, 0x0003 }, /* R1364 - AIF2 Frame Ctrl 14 */
|
||||
{ 0x00000555, 0x0004 }, /* R1365 - AIF2 Frame Ctrl 15 */
|
||||
{ 0x00000556, 0x0005 }, /* R1366 - AIF2 Frame Ctrl 16 */
|
||||
{ 0x00000559, 0x0000 }, /* R1369 - AIF2 Tx Enables */
|
||||
{ 0x0000055A, 0x0000 }, /* R1370 - AIF2 Rx Enables */
|
||||
{ 0x00000580, 0x000C }, /* R1408 - AIF3 BCLK Ctrl */
|
||||
@ -1790,6 +1798,8 @@ static bool wm5110_readable_register(struct device *dev, unsigned int reg)
|
||||
case ARIZONA_MIC_BIAS_CTRL_1:
|
||||
case ARIZONA_MIC_BIAS_CTRL_2:
|
||||
case ARIZONA_MIC_BIAS_CTRL_3:
|
||||
case ARIZONA_HP_CTRL_1L:
|
||||
case ARIZONA_HP_CTRL_1R:
|
||||
case ARIZONA_ACCESSORY_DETECT_MODE_1:
|
||||
case ARIZONA_HEADPHONE_DETECT_1:
|
||||
case ARIZONA_HEADPHONE_DETECT_2:
|
||||
@ -1934,8 +1944,16 @@ static bool wm5110_readable_register(struct device *dev, unsigned int reg)
|
||||
case ARIZONA_AIF2_FRAME_CTRL_2:
|
||||
case ARIZONA_AIF2_FRAME_CTRL_3:
|
||||
case ARIZONA_AIF2_FRAME_CTRL_4:
|
||||
case ARIZONA_AIF2_FRAME_CTRL_5:
|
||||
case ARIZONA_AIF2_FRAME_CTRL_6:
|
||||
case ARIZONA_AIF2_FRAME_CTRL_7:
|
||||
case ARIZONA_AIF2_FRAME_CTRL_8:
|
||||
case ARIZONA_AIF2_FRAME_CTRL_11:
|
||||
case ARIZONA_AIF2_FRAME_CTRL_12:
|
||||
case ARIZONA_AIF2_FRAME_CTRL_13:
|
||||
case ARIZONA_AIF2_FRAME_CTRL_14:
|
||||
case ARIZONA_AIF2_FRAME_CTRL_15:
|
||||
case ARIZONA_AIF2_FRAME_CTRL_16:
|
||||
case ARIZONA_AIF2_TX_ENABLES:
|
||||
case ARIZONA_AIF2_RX_ENABLES:
|
||||
case ARIZONA_AIF3_BCLK_CTRL:
|
||||
@ -2825,6 +2843,8 @@ static bool wm5110_volatile_register(struct device *dev, unsigned int reg)
|
||||
case ARIZONA_ASYNC_SAMPLE_RATE_1_STATUS:
|
||||
case ARIZONA_ASYNC_SAMPLE_RATE_2_STATUS:
|
||||
case ARIZONA_MIC_DETECT_3:
|
||||
case ARIZONA_HP_CTRL_1L:
|
||||
case ARIZONA_HP_CTRL_1R:
|
||||
case ARIZONA_HEADPHONE_DETECT_2:
|
||||
case ARIZONA_INPUT_ENABLES_STATUS:
|
||||
case ARIZONA_OUTPUT_STATUS_1:
|
||||
|
@ -308,7 +308,7 @@ int wm8350_device_init(struct wm8350 *wm8350, int irq,
|
||||
goto err;
|
||||
}
|
||||
|
||||
mode = id2 & WM8350_CONF_STS_MASK >> 10;
|
||||
mode = (id2 & WM8350_CONF_STS_MASK) >> 10;
|
||||
cust_id = id2 & WM8350_CUST_ID_MASK;
|
||||
chip_rev = (id2 & WM8350_CHIP_REV_MASK) >> 12;
|
||||
dev_info(wm8350->dev,
|
||||
|
@ -670,6 +670,7 @@ static const struct reg_default wm8997_reg_default[] = {
|
||||
{ 0x00000C23, 0x0000 }, /* R3107 - Misc Pad Ctrl 4 */
|
||||
{ 0x00000C24, 0x0000 }, /* R3108 - Misc Pad Ctrl 5 */
|
||||
{ 0x00000D08, 0xFFFF }, /* R3336 - Interrupt Status 1 Mask */
|
||||
{ 0x00000D09, 0xFFFF }, /* R3337 - Interrupt Status 2 Mask */
|
||||
{ 0x00000D0A, 0xFFFF }, /* R3338 - Interrupt Status 3 Mask */
|
||||
{ 0x00000D0B, 0xFFFF }, /* R3339 - Interrupt Status 4 Mask */
|
||||
{ 0x00000D0C, 0xFEFF }, /* R3340 - Interrupt Status 5 Mask */
|
||||
@ -886,6 +887,8 @@ static bool wm8997_readable_register(struct device *dev, unsigned int reg)
|
||||
case ARIZONA_MIC_BIAS_CTRL_1:
|
||||
case ARIZONA_MIC_BIAS_CTRL_2:
|
||||
case ARIZONA_MIC_BIAS_CTRL_3:
|
||||
case ARIZONA_HP_CTRL_1L:
|
||||
case ARIZONA_HP_CTRL_1R:
|
||||
case ARIZONA_ACCESSORY_DETECT_MODE_1:
|
||||
case ARIZONA_HEADPHONE_DETECT_1:
|
||||
case ARIZONA_HEADPHONE_DETECT_2:
|
||||
@ -1328,6 +1331,7 @@ static bool wm8997_readable_register(struct device *dev, unsigned int reg)
|
||||
case ARIZONA_INTERRUPT_STATUS_4:
|
||||
case ARIZONA_INTERRUPT_STATUS_5:
|
||||
case ARIZONA_INTERRUPT_STATUS_1_MASK:
|
||||
case ARIZONA_INTERRUPT_STATUS_2_MASK:
|
||||
case ARIZONA_INTERRUPT_STATUS_3_MASK:
|
||||
case ARIZONA_INTERRUPT_STATUS_4_MASK:
|
||||
case ARIZONA_INTERRUPT_STATUS_5_MASK:
|
||||
@ -1477,6 +1481,8 @@ static bool wm8997_volatile_register(struct device *dev, unsigned int reg)
|
||||
case ARIZONA_SAMPLE_RATE_3_STATUS:
|
||||
case ARIZONA_ASYNC_SAMPLE_RATE_1_STATUS:
|
||||
case ARIZONA_MIC_DETECT_3:
|
||||
case ARIZONA_HP_CTRL_1L:
|
||||
case ARIZONA_HP_CTRL_1R:
|
||||
case ARIZONA_HEADPHONE_DETECT_2:
|
||||
case ARIZONA_INPUT_ENABLES_STATUS:
|
||||
case ARIZONA_OUTPUT_STATUS_1:
|
||||
|
@ -529,13 +529,13 @@ config REGULATOR_S2MPA01
|
||||
via I2C bus. S2MPA01 has 10 Bucks and 26 LDO outputs.
|
||||
|
||||
config REGULATOR_S2MPS11
|
||||
tristate "Samsung S2MPS11/S2MPS14/S2MPU02 voltage regulator"
|
||||
tristate "Samsung S2MPS11/S2MPS13/S2MPS14/S2MPU02 voltage regulator"
|
||||
depends on MFD_SEC_CORE
|
||||
help
|
||||
This driver supports a Samsung S2MPS11/S2MPS14/S2MPU02 voltage output
|
||||
regulator via I2C bus. The chip is comprised of high efficient Buck
|
||||
converters including Dual-Phase Buck converter, Buck-Boost converter,
|
||||
various LDOs.
|
||||
This driver supports a Samsung S2MPS11/S2MPS13/S2MPS14/S2MPU02 voltage
|
||||
output regulator via I2C bus. The chip is comprised of high efficient
|
||||
Buck converters including Dual-Phase Buck converter, Buck-Boost
|
||||
converter, various LDOs.
|
||||
|
||||
config REGULATOR_S5M8767
|
||||
tristate "Samsung S5M8767A voltage regulator"
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/mfd/samsung/core.h>
|
||||
#include <linux/mfd/samsung/s2mps11.h>
|
||||
#include <linux/mfd/samsung/s2mps13.h>
|
||||
#include <linux/mfd/samsung/s2mps14.h>
|
||||
#include <linux/mfd/samsung/s2mpu02.h>
|
||||
|
||||
@ -45,10 +46,10 @@ struct s2mps11_info {
|
||||
enum sec_device_type dev_type;
|
||||
|
||||
/*
|
||||
* One bit for each S2MPS14/S2MPU02 regulator whether the suspend mode
|
||||
* was enabled.
|
||||
* One bit for each S2MPS13/S2MPS14/S2MPU02 regulator whether
|
||||
* the suspend mode was enabled.
|
||||
*/
|
||||
unsigned long long s2mps14_suspend_state:35;
|
||||
unsigned long long s2mps14_suspend_state:50;
|
||||
|
||||
/* Array of size rdev_num with GPIO-s for external sleep control */
|
||||
int *ext_control_gpio;
|
||||
@ -369,12 +370,101 @@ static const struct regulator_desc s2mps11_regulators[] = {
|
||||
regulator_desc_s2mps11_buck6_10(10, MIN_750_MV, STEP_12_5_MV),
|
||||
};
|
||||
|
||||
static struct regulator_ops s2mps14_reg_ops;
|
||||
|
||||
#define regulator_desc_s2mps13_ldo(num, min, step, min_sel) { \
|
||||
.name = "LDO"#num, \
|
||||
.id = S2MPS13_LDO##num, \
|
||||
.ops = &s2mps14_reg_ops, \
|
||||
.type = REGULATOR_VOLTAGE, \
|
||||
.owner = THIS_MODULE, \
|
||||
.min_uV = min, \
|
||||
.uV_step = step, \
|
||||
.linear_min_sel = min_sel, \
|
||||
.n_voltages = S2MPS14_LDO_N_VOLTAGES, \
|
||||
.vsel_reg = S2MPS13_REG_L1CTRL + num - 1, \
|
||||
.vsel_mask = S2MPS14_LDO_VSEL_MASK, \
|
||||
.enable_reg = S2MPS13_REG_L1CTRL + num - 1, \
|
||||
.enable_mask = S2MPS14_ENABLE_MASK \
|
||||
}
|
||||
|
||||
#define regulator_desc_s2mps13_buck(num, min, step, min_sel) { \
|
||||
.name = "BUCK"#num, \
|
||||
.id = S2MPS13_BUCK##num, \
|
||||
.ops = &s2mps14_reg_ops, \
|
||||
.type = REGULATOR_VOLTAGE, \
|
||||
.owner = THIS_MODULE, \
|
||||
.min_uV = min, \
|
||||
.uV_step = step, \
|
||||
.linear_min_sel = min_sel, \
|
||||
.n_voltages = S2MPS14_BUCK_N_VOLTAGES, \
|
||||
.ramp_delay = S2MPS13_BUCK_RAMP_DELAY, \
|
||||
.vsel_reg = S2MPS13_REG_B1OUT + (num - 1) * 2, \
|
||||
.vsel_mask = S2MPS14_BUCK_VSEL_MASK, \
|
||||
.enable_reg = S2MPS13_REG_B1CTRL + (num - 1) * 2, \
|
||||
.enable_mask = S2MPS14_ENABLE_MASK \
|
||||
}
|
||||
|
||||
static const struct regulator_desc s2mps13_regulators[] = {
|
||||
regulator_desc_s2mps13_ldo(1, MIN_800_MV, STEP_12_5_MV, 0x00),
|
||||
regulator_desc_s2mps13_ldo(2, MIN_1400_MV, STEP_50_MV, 0x0C),
|
||||
regulator_desc_s2mps13_ldo(3, MIN_1000_MV, STEP_25_MV, 0x08),
|
||||
regulator_desc_s2mps13_ldo(4, MIN_800_MV, STEP_12_5_MV, 0x00),
|
||||
regulator_desc_s2mps13_ldo(5, MIN_800_MV, STEP_12_5_MV, 0x00),
|
||||
regulator_desc_s2mps13_ldo(6, MIN_800_MV, STEP_12_5_MV, 0x00),
|
||||
regulator_desc_s2mps13_ldo(7, MIN_1000_MV, STEP_25_MV, 0x08),
|
||||
regulator_desc_s2mps13_ldo(8, MIN_1000_MV, STEP_25_MV, 0x08),
|
||||
regulator_desc_s2mps13_ldo(9, MIN_1000_MV, STEP_25_MV, 0x08),
|
||||
regulator_desc_s2mps13_ldo(10, MIN_1400_MV, STEP_50_MV, 0x0C),
|
||||
regulator_desc_s2mps13_ldo(11, MIN_800_MV, STEP_25_MV, 0x10),
|
||||
regulator_desc_s2mps13_ldo(12, MIN_800_MV, STEP_25_MV, 0x10),
|
||||
regulator_desc_s2mps13_ldo(13, MIN_800_MV, STEP_25_MV, 0x10),
|
||||
regulator_desc_s2mps13_ldo(14, MIN_800_MV, STEP_12_5_MV, 0x00),
|
||||
regulator_desc_s2mps13_ldo(15, MIN_800_MV, STEP_12_5_MV, 0x00),
|
||||
regulator_desc_s2mps13_ldo(16, MIN_1400_MV, STEP_50_MV, 0x0C),
|
||||
regulator_desc_s2mps13_ldo(17, MIN_1400_MV, STEP_50_MV, 0x0C),
|
||||
regulator_desc_s2mps13_ldo(18, MIN_1000_MV, STEP_25_MV, 0x08),
|
||||
regulator_desc_s2mps13_ldo(19, MIN_1000_MV, STEP_25_MV, 0x08),
|
||||
regulator_desc_s2mps13_ldo(20, MIN_1400_MV, STEP_50_MV, 0x0C),
|
||||
regulator_desc_s2mps13_ldo(21, MIN_1000_MV, STEP_25_MV, 0x08),
|
||||
regulator_desc_s2mps13_ldo(22, MIN_1000_MV, STEP_25_MV, 0x08),
|
||||
regulator_desc_s2mps13_ldo(23, MIN_800_MV, STEP_12_5_MV, 0x00),
|
||||
regulator_desc_s2mps13_ldo(24, MIN_800_MV, STEP_12_5_MV, 0x00),
|
||||
regulator_desc_s2mps13_ldo(25, MIN_1400_MV, STEP_50_MV, 0x0C),
|
||||
regulator_desc_s2mps13_ldo(26, MIN_1400_MV, STEP_50_MV, 0x0C),
|
||||
regulator_desc_s2mps13_ldo(27, MIN_1400_MV, STEP_50_MV, 0x0C),
|
||||
regulator_desc_s2mps13_ldo(28, MIN_1000_MV, STEP_25_MV, 0x08),
|
||||
regulator_desc_s2mps13_ldo(29, MIN_1400_MV, STEP_50_MV, 0x0C),
|
||||
regulator_desc_s2mps13_ldo(30, MIN_1400_MV, STEP_50_MV, 0x0C),
|
||||
regulator_desc_s2mps13_ldo(31, MIN_1000_MV, STEP_25_MV, 0x08),
|
||||
regulator_desc_s2mps13_ldo(32, MIN_1000_MV, STEP_25_MV, 0x08),
|
||||
regulator_desc_s2mps13_ldo(33, MIN_1400_MV, STEP_50_MV, 0x0C),
|
||||
regulator_desc_s2mps13_ldo(34, MIN_1000_MV, STEP_25_MV, 0x08),
|
||||
regulator_desc_s2mps13_ldo(35, MIN_1400_MV, STEP_50_MV, 0x0C),
|
||||
regulator_desc_s2mps13_ldo(36, MIN_800_MV, STEP_12_5_MV, 0x00),
|
||||
regulator_desc_s2mps13_ldo(37, MIN_1000_MV, STEP_25_MV, 0x08),
|
||||
regulator_desc_s2mps13_ldo(38, MIN_1400_MV, STEP_50_MV, 0x0C),
|
||||
regulator_desc_s2mps13_ldo(39, MIN_1000_MV, STEP_25_MV, 0x08),
|
||||
regulator_desc_s2mps13_ldo(40, MIN_1400_MV, STEP_50_MV, 0x0C),
|
||||
regulator_desc_s2mps13_buck(1, MIN_500_MV, STEP_6_25_MV, 0x10),
|
||||
regulator_desc_s2mps13_buck(2, MIN_500_MV, STEP_6_25_MV, 0x10),
|
||||
regulator_desc_s2mps13_buck(3, MIN_500_MV, STEP_6_25_MV, 0x10),
|
||||
regulator_desc_s2mps13_buck(4, MIN_500_MV, STEP_6_25_MV, 0x10),
|
||||
regulator_desc_s2mps13_buck(5, MIN_500_MV, STEP_6_25_MV, 0x10),
|
||||
regulator_desc_s2mps13_buck(6, MIN_500_MV, STEP_6_25_MV, 0x10),
|
||||
regulator_desc_s2mps13_buck(7, MIN_500_MV, STEP_6_25_MV, 0x10),
|
||||
regulator_desc_s2mps13_buck(8, MIN_1000_MV, STEP_12_5_MV, 0x20),
|
||||
regulator_desc_s2mps13_buck(9, MIN_1000_MV, STEP_12_5_MV, 0x20),
|
||||
regulator_desc_s2mps13_buck(10, MIN_500_MV, STEP_6_25_MV, 0x10),
|
||||
};
|
||||
|
||||
static int s2mps14_regulator_enable(struct regulator_dev *rdev)
|
||||
{
|
||||
struct s2mps11_info *s2mps11 = rdev_get_drvdata(rdev);
|
||||
unsigned int val;
|
||||
|
||||
switch (s2mps11->dev_type) {
|
||||
case S2MPS13X:
|
||||
case S2MPS14X:
|
||||
if (s2mps11->s2mps14_suspend_state & (1 << rdev_get_id(rdev)))
|
||||
val = S2MPS14_ENABLE_SUSPEND;
|
||||
@ -406,6 +496,7 @@ static int s2mps14_regulator_set_suspend_disable(struct regulator_dev *rdev)
|
||||
|
||||
/* Below LDO should be always on or does not support suspend mode. */
|
||||
switch (s2mps11->dev_type) {
|
||||
case S2MPS13X:
|
||||
case S2MPS14X:
|
||||
switch (rdev_id) {
|
||||
case S2MPS14_LDO3:
|
||||
@ -831,6 +922,10 @@ static int s2mps11_pmic_probe(struct platform_device *pdev)
|
||||
s2mps11->rdev_num = ARRAY_SIZE(s2mps11_regulators);
|
||||
regulators = s2mps11_regulators;
|
||||
break;
|
||||
case S2MPS13X:
|
||||
s2mps11->rdev_num = ARRAY_SIZE(s2mps13_regulators);
|
||||
regulators = s2mps13_regulators;
|
||||
break;
|
||||
case S2MPS14X:
|
||||
s2mps11->rdev_num = ARRAY_SIZE(s2mps14_regulators);
|
||||
regulators = s2mps14_regulators;
|
||||
@ -927,6 +1022,7 @@ static int s2mps11_pmic_probe(struct platform_device *pdev)
|
||||
|
||||
static const struct platform_device_id s2mps11_pmic_id[] = {
|
||||
{ "s2mps11-pmic", S2MPS11X},
|
||||
{ "s2mps13-pmic", S2MPS13X},
|
||||
{ "s2mps14-pmic", S2MPS14X},
|
||||
{ "s2mpu02-pmic", S2MPU02},
|
||||
{ },
|
||||
|
@ -12,7 +12,6 @@
|
||||
|
||||
int ab8500_sysctrl_read(u16 reg, u8 *value);
|
||||
int ab8500_sysctrl_write(u16 reg, u8 mask, u8 value);
|
||||
void ab8500_restart(char mode, const char *cmd);
|
||||
|
||||
#else
|
||||
|
||||
|
@ -125,6 +125,8 @@
|
||||
#define ARIZONA_MIC_BIAS_CTRL_1 0x218
|
||||
#define ARIZONA_MIC_BIAS_CTRL_2 0x219
|
||||
#define ARIZONA_MIC_BIAS_CTRL_3 0x21A
|
||||
#define ARIZONA_HP_CTRL_1L 0x225
|
||||
#define ARIZONA_HP_CTRL_1R 0x226
|
||||
#define ARIZONA_ACCESSORY_DETECT_MODE_1 0x293
|
||||
#define ARIZONA_HEADPHONE_DETECT_1 0x29B
|
||||
#define ARIZONA_HEADPHONE_DETECT_2 0x29C
|
||||
@ -279,8 +281,16 @@
|
||||
#define ARIZONA_AIF2_FRAME_CTRL_2 0x548
|
||||
#define ARIZONA_AIF2_FRAME_CTRL_3 0x549
|
||||
#define ARIZONA_AIF2_FRAME_CTRL_4 0x54A
|
||||
#define ARIZONA_AIF2_FRAME_CTRL_5 0x54B
|
||||
#define ARIZONA_AIF2_FRAME_CTRL_6 0x54C
|
||||
#define ARIZONA_AIF2_FRAME_CTRL_7 0x54D
|
||||
#define ARIZONA_AIF2_FRAME_CTRL_8 0x54E
|
||||
#define ARIZONA_AIF2_FRAME_CTRL_11 0x551
|
||||
#define ARIZONA_AIF2_FRAME_CTRL_12 0x552
|
||||
#define ARIZONA_AIF2_FRAME_CTRL_13 0x553
|
||||
#define ARIZONA_AIF2_FRAME_CTRL_14 0x554
|
||||
#define ARIZONA_AIF2_FRAME_CTRL_15 0x555
|
||||
#define ARIZONA_AIF2_FRAME_CTRL_16 0x556
|
||||
#define ARIZONA_AIF2_TX_ENABLES 0x559
|
||||
#define ARIZONA_AIF2_RX_ENABLES 0x55A
|
||||
#define ARIZONA_AIF2_FORCE_WRITE 0x55B
|
||||
@ -2244,6 +2254,46 @@
|
||||
#define ARIZONA_MICB3_ENA_SHIFT 0 /* MICB3_ENA */
|
||||
#define ARIZONA_MICB3_ENA_WIDTH 1 /* MICB3_ENA */
|
||||
|
||||
/*
|
||||
* R549 (0x225) - HP Ctrl 1L
|
||||
*/
|
||||
#define ARIZONA_RMV_SHRT_HP1L 0x4000 /* RMV_SHRT_HP1L */
|
||||
#define ARIZONA_RMV_SHRT_HP1L_MASK 0x4000 /* RMV_SHRT_HP1L */
|
||||
#define ARIZONA_RMV_SHRT_HP1L_SHIFT 14 /* RMV_SHRT_HP1L */
|
||||
#define ARIZONA_RMV_SHRT_HP1L_WIDTH 1 /* RMV_SHRT_HP1L */
|
||||
#define ARIZONA_HP1L_FLWR 0x0004 /* HP1L_FLWR */
|
||||
#define ARIZONA_HP1L_FLWR_MASK 0x0004 /* HP1L_FLWR */
|
||||
#define ARIZONA_HP1L_FLWR_SHIFT 2 /* HP1L_FLWR */
|
||||
#define ARIZONA_HP1L_FLWR_WIDTH 1 /* HP1L_FLWR */
|
||||
#define ARIZONA_HP1L_SHRTI 0x0002 /* HP1L_SHRTI */
|
||||
#define ARIZONA_HP1L_SHRTI_MASK 0x0002 /* HP1L_SHRTI */
|
||||
#define ARIZONA_HP1L_SHRTI_SHIFT 1 /* HP1L_SHRTI */
|
||||
#define ARIZONA_HP1L_SHRTI_WIDTH 1 /* HP1L_SHRTI */
|
||||
#define ARIZONA_HP1L_SHRTO 0x0001 /* HP1L_SHRTO */
|
||||
#define ARIZONA_HP1L_SHRTO_MASK 0x0001 /* HP1L_SHRTO */
|
||||
#define ARIZONA_HP1L_SHRTO_SHIFT 0 /* HP1L_SHRTO */
|
||||
#define ARIZONA_HP1L_SHRTO_WIDTH 1 /* HP1L_SHRTO */
|
||||
|
||||
/*
|
||||
* R550 (0x226) - HP Ctrl 1R
|
||||
*/
|
||||
#define ARIZONA_RMV_SHRT_HP1R 0x4000 /* RMV_SHRT_HP1R */
|
||||
#define ARIZONA_RMV_SHRT_HP1R_MASK 0x4000 /* RMV_SHRT_HP1R */
|
||||
#define ARIZONA_RMV_SHRT_HP1R_SHIFT 14 /* RMV_SHRT_HP1R */
|
||||
#define ARIZONA_RMV_SHRT_HP1R_WIDTH 1 /* RMV_SHRT_HP1R */
|
||||
#define ARIZONA_HP1R_FLWR 0x0004 /* HP1R_FLWR */
|
||||
#define ARIZONA_HP1R_FLWR_MASK 0x0004 /* HP1R_FLWR */
|
||||
#define ARIZONA_HP1R_FLWR_SHIFT 2 /* HP1R_FLWR */
|
||||
#define ARIZONA_HP1R_FLWR_WIDTH 1 /* HP1R_FLWR */
|
||||
#define ARIZONA_HP1R_SHRTI 0x0002 /* HP1R_SHRTI */
|
||||
#define ARIZONA_HP1R_SHRTI_MASK 0x0002 /* HP1R_SHRTI */
|
||||
#define ARIZONA_HP1R_SHRTI_SHIFT 1 /* HP1R_SHRTI */
|
||||
#define ARIZONA_HP1R_SHRTI_WIDTH 1 /* HP1R_SHRTI */
|
||||
#define ARIZONA_HP1R_SHRTO 0x0001 /* HP1R_SHRTO */
|
||||
#define ARIZONA_HP1R_SHRTO_MASK 0x0001 /* HP1R_SHRTO */
|
||||
#define ARIZONA_HP1R_SHRTO_SHIFT 0 /* HP1R_SHRTO */
|
||||
#define ARIZONA_HP1R_SHRTO_WIDTH 1 /* HP1R_SHRTO */
|
||||
|
||||
/*
|
||||
* R659 (0x293) - Accessory Detect Mode 1
|
||||
*/
|
||||
|
85
include/linux/mfd/atmel-hlcdc.h
Normal file
85
include/linux/mfd/atmel-hlcdc.h
Normal file
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Free Electrons
|
||||
* Copyright (C) 2014 Atmel
|
||||
*
|
||||
* Author: Boris BREZILLON <boris.brezillon@free-electrons.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.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of 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. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_MFD_HLCDC_H
|
||||
#define __LINUX_MFD_HLCDC_H
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#define ATMEL_HLCDC_CFG(i) ((i) * 0x4)
|
||||
#define ATMEL_HLCDC_SIG_CFG LCDCFG(5)
|
||||
#define ATMEL_HLCDC_HSPOL BIT(0)
|
||||
#define ATMEL_HLCDC_VSPOL BIT(1)
|
||||
#define ATMEL_HLCDC_VSPDLYS BIT(2)
|
||||
#define ATMEL_HLCDC_VSPDLYE BIT(3)
|
||||
#define ATMEL_HLCDC_DISPPOL BIT(4)
|
||||
#define ATMEL_HLCDC_DITHER BIT(6)
|
||||
#define ATMEL_HLCDC_DISPDLY BIT(7)
|
||||
#define ATMEL_HLCDC_MODE_MASK GENMASK(9, 8)
|
||||
#define ATMEL_HLCDC_PP BIT(10)
|
||||
#define ATMEL_HLCDC_VSPSU BIT(12)
|
||||
#define ATMEL_HLCDC_VSPHO BIT(13)
|
||||
#define ATMEL_HLCDC_GUARDTIME_MASK GENMASK(20, 16)
|
||||
|
||||
#define ATMEL_HLCDC_EN 0x20
|
||||
#define ATMEL_HLCDC_DIS 0x24
|
||||
#define ATMEL_HLCDC_SR 0x28
|
||||
#define ATMEL_HLCDC_IER 0x2c
|
||||
#define ATMEL_HLCDC_IDR 0x30
|
||||
#define ATMEL_HLCDC_IMR 0x34
|
||||
#define ATMEL_HLCDC_ISR 0x38
|
||||
|
||||
#define ATMEL_HLCDC_CLKPOL BIT(0)
|
||||
#define ATMEL_HLCDC_CLKSEL BIT(2)
|
||||
#define ATMEL_HLCDC_CLKPWMSEL BIT(3)
|
||||
#define ATMEL_HLCDC_CGDIS(i) BIT(8 + (i))
|
||||
#define ATMEL_HLCDC_CLKDIV_SHFT 16
|
||||
#define ATMEL_HLCDC_CLKDIV_MASK GENMASK(23, 16)
|
||||
#define ATMEL_HLCDC_CLKDIV(div) ((div - 2) << ATMEL_HLCDC_CLKDIV_SHFT)
|
||||
|
||||
#define ATMEL_HLCDC_PIXEL_CLK BIT(0)
|
||||
#define ATMEL_HLCDC_SYNC BIT(1)
|
||||
#define ATMEL_HLCDC_DISP BIT(2)
|
||||
#define ATMEL_HLCDC_PWM BIT(3)
|
||||
#define ATMEL_HLCDC_SIP BIT(4)
|
||||
|
||||
#define ATMEL_HLCDC_SOF BIT(0)
|
||||
#define ATMEL_HLCDC_SYNCDIS BIT(1)
|
||||
#define ATMEL_HLCDC_FIFOERR BIT(4)
|
||||
#define ATMEL_HLCDC_LAYER_STATUS(x) BIT((x) + 8)
|
||||
|
||||
/**
|
||||
* Structure shared by the MFD device and its subdevices.
|
||||
*
|
||||
* @regmap: register map used to access HLCDC IP registers
|
||||
* @periph_clk: the hlcdc peripheral clock
|
||||
* @sys_clk: the hlcdc system clock
|
||||
* @slow_clk: the system slow clk
|
||||
* @irq: the hlcdc irq
|
||||
*/
|
||||
struct atmel_hlcdc {
|
||||
struct regmap *regmap;
|
||||
struct clk *periph_clk;
|
||||
struct clk *sys_clk;
|
||||
struct clk *slow_clk;
|
||||
int irq;
|
||||
};
|
||||
|
||||
#endif /* __LINUX_MFD_HLCDC_H */
|
@ -14,6 +14,8 @@
|
||||
enum {
|
||||
AXP202_ID = 0,
|
||||
AXP209_ID,
|
||||
AXP288_ID,
|
||||
NR_AXP20X_VARIANTS,
|
||||
};
|
||||
|
||||
#define AXP20X_DATACACHE(m) (0x04 + (m))
|
||||
@ -49,11 +51,13 @@ enum {
|
||||
#define AXP20X_IRQ3_EN 0x42
|
||||
#define AXP20X_IRQ4_EN 0x43
|
||||
#define AXP20X_IRQ5_EN 0x44
|
||||
#define AXP20X_IRQ6_EN 0x45
|
||||
#define AXP20X_IRQ1_STATE 0x48
|
||||
#define AXP20X_IRQ2_STATE 0x49
|
||||
#define AXP20X_IRQ3_STATE 0x4a
|
||||
#define AXP20X_IRQ4_STATE 0x4b
|
||||
#define AXP20X_IRQ5_STATE 0x4c
|
||||
#define AXP20X_IRQ6_STATE 0x4d
|
||||
|
||||
/* ADC */
|
||||
#define AXP20X_ACIN_V_ADC_H 0x56
|
||||
@ -116,6 +120,15 @@ enum {
|
||||
#define AXP20X_CC_CTRL 0xb8
|
||||
#define AXP20X_FG_RES 0xb9
|
||||
|
||||
/* AXP288 specific registers */
|
||||
#define AXP288_PMIC_ADC_H 0x56
|
||||
#define AXP288_PMIC_ADC_L 0x57
|
||||
#define AXP288_ADC_TS_PIN_CTRL 0x84
|
||||
|
||||
#define AXP288_PMIC_ADC_EN 0x84
|
||||
#define AXP288_FG_TUNE5 0xed
|
||||
|
||||
|
||||
/* Regulators IDs */
|
||||
enum {
|
||||
AXP20X_LDO1 = 0,
|
||||
@ -169,12 +182,58 @@ enum {
|
||||
AXP20X_IRQ_GPIO0_INPUT,
|
||||
};
|
||||
|
||||
enum axp288_irqs {
|
||||
AXP288_IRQ_VBUS_FALL = 2,
|
||||
AXP288_IRQ_VBUS_RISE,
|
||||
AXP288_IRQ_OV,
|
||||
AXP288_IRQ_FALLING_ALT,
|
||||
AXP288_IRQ_RISING_ALT,
|
||||
AXP288_IRQ_OV_ALT,
|
||||
AXP288_IRQ_DONE = 10,
|
||||
AXP288_IRQ_CHARGING,
|
||||
AXP288_IRQ_SAFE_QUIT,
|
||||
AXP288_IRQ_SAFE_ENTER,
|
||||
AXP288_IRQ_ABSENT,
|
||||
AXP288_IRQ_APPEND,
|
||||
AXP288_IRQ_QWBTU,
|
||||
AXP288_IRQ_WBTU,
|
||||
AXP288_IRQ_QWBTO,
|
||||
AXP288_IRQ_WBTO,
|
||||
AXP288_IRQ_QCBTU,
|
||||
AXP288_IRQ_CBTU,
|
||||
AXP288_IRQ_QCBTO,
|
||||
AXP288_IRQ_CBTO,
|
||||
AXP288_IRQ_WL2,
|
||||
AXP288_IRQ_WL1,
|
||||
AXP288_IRQ_GPADC,
|
||||
AXP288_IRQ_OT = 31,
|
||||
AXP288_IRQ_GPIO0,
|
||||
AXP288_IRQ_GPIO1,
|
||||
AXP288_IRQ_POKO,
|
||||
AXP288_IRQ_POKL,
|
||||
AXP288_IRQ_POKS,
|
||||
AXP288_IRQ_POKN,
|
||||
AXP288_IRQ_POKP,
|
||||
AXP288_IRQ_TIMER,
|
||||
AXP288_IRQ_MV_CHNG,
|
||||
AXP288_IRQ_BC_USB_CHNG,
|
||||
};
|
||||
|
||||
#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;
|
||||
struct i2c_client *i2c_client;
|
||||
struct regmap *regmap;
|
||||
struct regmap_irq_chip_data *regmap_irqc;
|
||||
long variant;
|
||||
int nr_cells;
|
||||
struct mfd_cell *cells;
|
||||
const struct regmap_config *regmap_cfg;
|
||||
const struct regmap_irq_chip *regmap_irq_chip;
|
||||
};
|
||||
|
||||
#endif /* __LINUX_MFD_AXP20X_H */
|
||||
|
@ -111,6 +111,13 @@ extern int mfd_add_devices(struct device *parent, int id,
|
||||
struct resource *mem_base,
|
||||
int irq_base, struct irq_domain *irq_domain);
|
||||
|
||||
static inline int mfd_add_hotplug_devices(struct device *parent,
|
||||
const struct mfd_cell *cells, int n_devs)
|
||||
{
|
||||
return mfd_add_devices(parent, PLATFORM_DEVID_AUTO, cells, n_devs,
|
||||
NULL, 0, NULL);
|
||||
}
|
||||
|
||||
extern void mfd_remove_devices(struct device *parent);
|
||||
|
||||
#endif
|
||||
|
103
include/linux/mfd/dln2.h
Normal file
103
include/linux/mfd/dln2.h
Normal file
@ -0,0 +1,103 @@
|
||||
#ifndef __LINUX_USB_DLN2_H
|
||||
#define __LINUX_USB_DLN2_H
|
||||
|
||||
#define DLN2_CMD(cmd, id) ((cmd) | ((id) << 8))
|
||||
|
||||
struct dln2_platform_data {
|
||||
u16 handle; /* sub-driver handle (internally used only) */
|
||||
u8 port; /* I2C/SPI port */
|
||||
};
|
||||
|
||||
/**
|
||||
* dln2_event_cb_t - event callback function signature
|
||||
*
|
||||
* @pdev - the sub-device that registered this callback
|
||||
* @echo - the echo header field received in the message
|
||||
* @data - the data payload
|
||||
* @len - the data payload length
|
||||
*
|
||||
* The callback function is called in interrupt context and the data payload is
|
||||
* only valid during the call. If the user needs later access of the data, it
|
||||
* must copy it.
|
||||
*/
|
||||
|
||||
typedef void (*dln2_event_cb_t)(struct platform_device *pdev, u16 echo,
|
||||
const void *data, int len);
|
||||
|
||||
/**
|
||||
* dl2n_register_event_cb - register a callback function for an event
|
||||
*
|
||||
* @pdev - the sub-device that registers the callback
|
||||
* @event - the event for which to register a callback
|
||||
* @event_cb - the callback function
|
||||
*
|
||||
* @return 0 in case of success, negative value in case of error
|
||||
*/
|
||||
int dln2_register_event_cb(struct platform_device *pdev, u16 event,
|
||||
dln2_event_cb_t event_cb);
|
||||
|
||||
/**
|
||||
* dln2_unregister_event_cb - unregister the callback function for an event
|
||||
*
|
||||
* @pdev - the sub-device that registered the callback
|
||||
* @event - the event for which to register a callback
|
||||
*/
|
||||
void dln2_unregister_event_cb(struct platform_device *pdev, u16 event);
|
||||
|
||||
/**
|
||||
* dln2_transfer - issue a DLN2 command and wait for a response and the
|
||||
* associated data
|
||||
*
|
||||
* @pdev - the sub-device which is issuing this transfer
|
||||
* @cmd - the command to be sent to the device
|
||||
* @obuf - the buffer to be sent to the device; it can be NULL if the user
|
||||
* doesn't need to transmit data with this command
|
||||
* @obuf_len - the size of the buffer to be sent to the device
|
||||
* @ibuf - any data associated with the response will be copied here; it can be
|
||||
* NULL if the user doesn't need the response data
|
||||
* @ibuf_len - must be initialized to the input buffer size; it will be modified
|
||||
* to indicate the actual data transferred;
|
||||
*
|
||||
* @return 0 for success, negative value for errors
|
||||
*/
|
||||
int dln2_transfer(struct platform_device *pdev, u16 cmd,
|
||||
const void *obuf, unsigned obuf_len,
|
||||
void *ibuf, unsigned *ibuf_len);
|
||||
|
||||
/**
|
||||
* dln2_transfer_rx - variant of @dln2_transfer() where TX buffer is not needed
|
||||
*
|
||||
* @pdev - the sub-device which is issuing this transfer
|
||||
* @cmd - the command to be sent to the device
|
||||
* @ibuf - any data associated with the response will be copied here; it can be
|
||||
* NULL if the user doesn't need the response data
|
||||
* @ibuf_len - must be initialized to the input buffer size; it will be modified
|
||||
* to indicate the actual data transferred;
|
||||
*
|
||||
* @return 0 for success, negative value for errors
|
||||
*/
|
||||
|
||||
static inline int dln2_transfer_rx(struct platform_device *pdev, u16 cmd,
|
||||
void *ibuf, unsigned *ibuf_len)
|
||||
{
|
||||
return dln2_transfer(pdev, cmd, NULL, 0, ibuf, ibuf_len);
|
||||
}
|
||||
|
||||
/**
|
||||
* dln2_transfer_tx - variant of @dln2_transfer() where RX buffer is not needed
|
||||
*
|
||||
* @pdev - the sub-device which is issuing this transfer
|
||||
* @cmd - the command to be sent to the device
|
||||
* @obuf - the buffer to be sent to the device; it can be NULL if the
|
||||
* user doesn't need to transmit data with this command
|
||||
* @obuf_len - the size of the buffer to be sent to the device
|
||||
*
|
||||
* @return 0 for success, negative value for errors
|
||||
*/
|
||||
static inline int dln2_transfer_tx(struct platform_device *pdev, u16 cmd,
|
||||
const void *obuf, unsigned obuf_len)
|
||||
{
|
||||
return dln2_transfer(pdev, cmd, obuf, obuf_len, NULL, NULL);
|
||||
}
|
||||
|
||||
#endif
|
@ -26,7 +26,6 @@
|
||||
|
||||
#include <linux/i2c.h>
|
||||
|
||||
#define MAX77693_NUM_IRQ_MUIC_REGS 3
|
||||
#define MAX77693_REG_INVALID (0xff)
|
||||
|
||||
/* Slave addr = 0xCC: PMIC, Charger, Flash LED */
|
||||
|
@ -558,6 +558,7 @@
|
||||
#define SD_SAMPLE_POINT_CTL 0xFDA7
|
||||
#define SD_PUSH_POINT_CTL 0xFDA8
|
||||
#define SD_CMD0 0xFDA9
|
||||
#define SD_CMD_START 0x40
|
||||
#define SD_CMD1 0xFDAA
|
||||
#define SD_CMD2 0xFDAB
|
||||
#define SD_CMD3 0xFDAC
|
||||
@ -707,6 +708,14 @@
|
||||
#define PM_CTRL1 0xFF44
|
||||
#define PM_CTRL2 0xFF45
|
||||
#define PM_CTRL3 0xFF46
|
||||
#define SDIO_SEND_PME_EN 0x80
|
||||
#define FORCE_RC_MODE_ON 0x40
|
||||
#define FORCE_RX50_LINK_ON 0x20
|
||||
#define D3_DELINK_MODE_EN 0x10
|
||||
#define USE_PESRTB_CTL_DELINK 0x08
|
||||
#define DELAY_PIN_WAKE 0x04
|
||||
#define RESET_PIN_WAKE 0x02
|
||||
#define PM_WAKE_EN 0x01
|
||||
#define PM_CTRL4 0xFF47
|
||||
|
||||
/* Memory mapping */
|
||||
@ -752,6 +761,14 @@
|
||||
#define PHY_DUM_REG 0x1F
|
||||
|
||||
#define LCTLR 0x80
|
||||
#define LCTLR_EXT_SYNC 0x80
|
||||
#define LCTLR_COMMON_CLOCK_CFG 0x40
|
||||
#define LCTLR_RETRAIN_LINK 0x20
|
||||
#define LCTLR_LINK_DISABLE 0x10
|
||||
#define LCTLR_RCB 0x08
|
||||
#define LCTLR_RESERVED 0x04
|
||||
#define LCTLR_ASPM_CTL_MASK 0x03
|
||||
|
||||
#define PCR_SETTING_REG1 0x724
|
||||
#define PCR_SETTING_REG2 0x814
|
||||
#define PCR_SETTING_REG3 0x747
|
||||
@ -967,4 +984,24 @@ static inline u8 *rtsx_pci_get_cmd_data(struct rtsx_pcr *pcr)
|
||||
return (u8 *)(pcr->host_cmds_ptr);
|
||||
}
|
||||
|
||||
static inline int rtsx_pci_update_cfg_byte(struct rtsx_pcr *pcr, int addr,
|
||||
u8 mask, u8 append)
|
||||
{
|
||||
int err;
|
||||
u8 val;
|
||||
|
||||
err = pci_read_config_byte(pcr->pci, addr, &val);
|
||||
if (err < 0)
|
||||
return err;
|
||||
return pci_write_config_byte(pcr->pci, addr, (val & mask) | append);
|
||||
}
|
||||
|
||||
static inline void rtsx_pci_write_be32(struct rtsx_pcr *pcr, u16 reg, u32 val)
|
||||
{
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, reg, 0xFF, val >> 24);
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, reg + 1, 0xFF, val >> 16);
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, reg + 2, 0xFF, val >> 8);
|
||||
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, reg + 3, 0xFF, val);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -28,6 +28,7 @@
|
||||
#define MIN_800_MV 800000
|
||||
#define MIN_750_MV 750000
|
||||
#define MIN_600_MV 600000
|
||||
#define MIN_500_MV 500000
|
||||
|
||||
/* Macros to represent steps for LDO/BUCK */
|
||||
#define STEP_50_MV 50000
|
||||
@ -41,6 +42,7 @@ enum sec_device_type {
|
||||
S5M8767X,
|
||||
S2MPA01,
|
||||
S2MPS11X,
|
||||
S2MPS13X,
|
||||
S2MPS14X,
|
||||
S2MPU02,
|
||||
};
|
||||
|
186
include/linux/mfd/samsung/s2mps13.h
Normal file
186
include/linux/mfd/samsung/s2mps13.h
Normal file
@ -0,0 +1,186 @@
|
||||
/*
|
||||
* s2mps13.h
|
||||
*
|
||||
* Copyright (c) 2014 Samsung Electronics Co., Ltd
|
||||
* http://www.samsung.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; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_MFD_S2MPS13_H
|
||||
#define __LINUX_MFD_S2MPS13_H
|
||||
|
||||
/* S2MPS13 registers */
|
||||
enum s2mps13_reg {
|
||||
S2MPS13_REG_ID,
|
||||
S2MPS13_REG_INT1,
|
||||
S2MPS13_REG_INT2,
|
||||
S2MPS13_REG_INT3,
|
||||
S2MPS13_REG_INT1M,
|
||||
S2MPS13_REG_INT2M,
|
||||
S2MPS13_REG_INT3M,
|
||||
S2MPS13_REG_ST1,
|
||||
S2MPS13_REG_ST2,
|
||||
S2MPS13_REG_PWRONSRC,
|
||||
S2MPS13_REG_OFFSRC,
|
||||
S2MPS13_REG_BU_CHG,
|
||||
S2MPS13_REG_RTCCTRL,
|
||||
S2MPS13_REG_CTRL1,
|
||||
S2MPS13_REG_CTRL2,
|
||||
S2MPS13_REG_RSVD1,
|
||||
S2MPS13_REG_RSVD2,
|
||||
S2MPS13_REG_RSVD3,
|
||||
S2MPS13_REG_RSVD4,
|
||||
S2MPS13_REG_RSVD5,
|
||||
S2MPS13_REG_RSVD6,
|
||||
S2MPS13_REG_CTRL3,
|
||||
S2MPS13_REG_RSVD7,
|
||||
S2MPS13_REG_RSVD8,
|
||||
S2MPS13_REG_WRSTBI,
|
||||
S2MPS13_REG_B1CTRL,
|
||||
S2MPS13_REG_B1OUT,
|
||||
S2MPS13_REG_B2CTRL,
|
||||
S2MPS13_REG_B2OUT,
|
||||
S2MPS13_REG_B3CTRL,
|
||||
S2MPS13_REG_B3OUT,
|
||||
S2MPS13_REG_B4CTRL,
|
||||
S2MPS13_REG_B4OUT,
|
||||
S2MPS13_REG_B5CTRL,
|
||||
S2MPS13_REG_B5OUT,
|
||||
S2MPS13_REG_B6CTRL,
|
||||
S2MPS13_REG_B6OUT,
|
||||
S2MPS13_REG_B7CTRL,
|
||||
S2MPS13_REG_B7OUT,
|
||||
S2MPS13_REG_B8CTRL,
|
||||
S2MPS13_REG_B8OUT,
|
||||
S2MPS13_REG_B9CTRL,
|
||||
S2MPS13_REG_B9OUT,
|
||||
S2MPS13_REG_B10CTRL,
|
||||
S2MPS13_REG_B10OUT,
|
||||
S2MPS13_REG_BB1CTRL,
|
||||
S2MPS13_REG_BB1OUT,
|
||||
S2MPS13_REG_BUCK_RAMP1,
|
||||
S2MPS13_REG_BUCK_RAMP2,
|
||||
S2MPS13_REG_LDO_DVS1,
|
||||
S2MPS13_REG_LDO_DVS2,
|
||||
S2MPS13_REG_LDO_DVS3,
|
||||
S2MPS13_REG_B6OUT2,
|
||||
S2MPS13_REG_L1CTRL,
|
||||
S2MPS13_REG_L2CTRL,
|
||||
S2MPS13_REG_L3CTRL,
|
||||
S2MPS13_REG_L4CTRL,
|
||||
S2MPS13_REG_L5CTRL,
|
||||
S2MPS13_REG_L6CTRL,
|
||||
S2MPS13_REG_L7CTRL,
|
||||
S2MPS13_REG_L8CTRL,
|
||||
S2MPS13_REG_L9CTRL,
|
||||
S2MPS13_REG_L10CTRL,
|
||||
S2MPS13_REG_L11CTRL,
|
||||
S2MPS13_REG_L12CTRL,
|
||||
S2MPS13_REG_L13CTRL,
|
||||
S2MPS13_REG_L14CTRL,
|
||||
S2MPS13_REG_L15CTRL,
|
||||
S2MPS13_REG_L16CTRL,
|
||||
S2MPS13_REG_L17CTRL,
|
||||
S2MPS13_REG_L18CTRL,
|
||||
S2MPS13_REG_L19CTRL,
|
||||
S2MPS13_REG_L20CTRL,
|
||||
S2MPS13_REG_L21CTRL,
|
||||
S2MPS13_REG_L22CTRL,
|
||||
S2MPS13_REG_L23CTRL,
|
||||
S2MPS13_REG_L24CTRL,
|
||||
S2MPS13_REG_L25CTRL,
|
||||
S2MPS13_REG_L26CTRL,
|
||||
S2MPS13_REG_L27CTRL,
|
||||
S2MPS13_REG_L28CTRL,
|
||||
S2MPS13_REG_L30CTRL,
|
||||
S2MPS13_REG_L31CTRL,
|
||||
S2MPS13_REG_L32CTRL,
|
||||
S2MPS13_REG_L33CTRL,
|
||||
S2MPS13_REG_L34CTRL,
|
||||
S2MPS13_REG_L35CTRL,
|
||||
S2MPS13_REG_L36CTRL,
|
||||
S2MPS13_REG_L37CTRL,
|
||||
S2MPS13_REG_L38CTRL,
|
||||
S2MPS13_REG_L39CTRL,
|
||||
S2MPS13_REG_L40CTRL,
|
||||
S2MPS13_REG_LDODSCH1,
|
||||
S2MPS13_REG_LDODSCH2,
|
||||
S2MPS13_REG_LDODSCH3,
|
||||
S2MPS13_REG_LDODSCH4,
|
||||
S2MPS13_REG_LDODSCH5,
|
||||
};
|
||||
|
||||
/* regulator ids */
|
||||
enum s2mps13_regulators {
|
||||
S2MPS13_LDO1,
|
||||
S2MPS13_LDO2,
|
||||
S2MPS13_LDO3,
|
||||
S2MPS13_LDO4,
|
||||
S2MPS13_LDO5,
|
||||
S2MPS13_LDO6,
|
||||
S2MPS13_LDO7,
|
||||
S2MPS13_LDO8,
|
||||
S2MPS13_LDO9,
|
||||
S2MPS13_LDO10,
|
||||
S2MPS13_LDO11,
|
||||
S2MPS13_LDO12,
|
||||
S2MPS13_LDO13,
|
||||
S2MPS13_LDO14,
|
||||
S2MPS13_LDO15,
|
||||
S2MPS13_LDO16,
|
||||
S2MPS13_LDO17,
|
||||
S2MPS13_LDO18,
|
||||
S2MPS13_LDO19,
|
||||
S2MPS13_LDO20,
|
||||
S2MPS13_LDO21,
|
||||
S2MPS13_LDO22,
|
||||
S2MPS13_LDO23,
|
||||
S2MPS13_LDO24,
|
||||
S2MPS13_LDO25,
|
||||
S2MPS13_LDO26,
|
||||
S2MPS13_LDO27,
|
||||
S2MPS13_LDO28,
|
||||
S2MPS13_LDO29,
|
||||
S2MPS13_LDO30,
|
||||
S2MPS13_LDO31,
|
||||
S2MPS13_LDO32,
|
||||
S2MPS13_LDO33,
|
||||
S2MPS13_LDO34,
|
||||
S2MPS13_LDO35,
|
||||
S2MPS13_LDO36,
|
||||
S2MPS13_LDO37,
|
||||
S2MPS13_LDO38,
|
||||
S2MPS13_LDO39,
|
||||
S2MPS13_LDO40,
|
||||
S2MPS13_BUCK1,
|
||||
S2MPS13_BUCK2,
|
||||
S2MPS13_BUCK3,
|
||||
S2MPS13_BUCK4,
|
||||
S2MPS13_BUCK5,
|
||||
S2MPS13_BUCK6,
|
||||
S2MPS13_BUCK7,
|
||||
S2MPS13_BUCK8,
|
||||
S2MPS13_BUCK9,
|
||||
S2MPS13_BUCK10,
|
||||
|
||||
S2MPS13_REGULATOR_MAX,
|
||||
};
|
||||
|
||||
/*
|
||||
* Default ramp delay in uv/us. Datasheet says that ramp delay can be
|
||||
* controlled however it does not specify which register is used for that.
|
||||
* Let's assume that default value will be set.
|
||||
*/
|
||||
#define S2MPS13_BUCK_RAMP_DELAY 12500
|
||||
|
||||
#endif /* __LINUX_MFD_S2MPS13_H */
|
@ -164,13 +164,10 @@ struct tc3589x_keypad_platform_data {
|
||||
|
||||
/**
|
||||
* struct tc3589x_gpio_platform_data - TC3589x GPIO platform data
|
||||
* @gpio_base: first gpio number assigned to TC3589x. A maximum of
|
||||
* %TC3589x_NR_GPIOS GPIOs will be allocated.
|
||||
* @setup: callback for board-specific initialization
|
||||
* @remove: callback for board-specific teardown
|
||||
*/
|
||||
struct tc3589x_gpio_platform_data {
|
||||
int gpio_base;
|
||||
void (*setup)(struct tc3589x *tc3589x, unsigned gpio_base);
|
||||
void (*remove)(struct tc3589x *tc3589x, unsigned gpio_base);
|
||||
};
|
||||
@ -178,18 +175,13 @@ struct tc3589x_gpio_platform_data {
|
||||
/**
|
||||
* struct tc3589x_platform_data - TC3589x platform data
|
||||
* @block: bitmask of blocks to enable (use TC3589x_BLOCK_*)
|
||||
* @irq_base: base IRQ number. %TC3589x_NR_IRQS irqs will be used.
|
||||
* @gpio: GPIO-specific platform data
|
||||
* @keypad: keypad-specific platform data
|
||||
*/
|
||||
struct tc3589x_platform_data {
|
||||
unsigned int block;
|
||||
int irq_base;
|
||||
struct tc3589x_gpio_platform_data *gpio;
|
||||
const struct tc3589x_keypad_platform_data *keypad;
|
||||
};
|
||||
|
||||
#define TC3589x_NR_GPIOS 24
|
||||
#define TC3589x_NR_IRQS TC3589x_INT_GPIO(TC3589x_NR_GPIOS)
|
||||
|
||||
#endif
|
||||
|
@ -922,4 +922,15 @@ static inline int of_changeset_update_property(struct of_changeset *ocs,
|
||||
/* CONFIG_OF_RESOLVE api */
|
||||
extern int of_resolve_phandles(struct device_node *tree);
|
||||
|
||||
/**
|
||||
* of_system_has_poweroff_source - Tells if poweroff-source is found for device_node
|
||||
* @np: Pointer to the given device_node
|
||||
*
|
||||
* return true if present false otherwise
|
||||
*/
|
||||
static inline bool of_system_has_poweroff_source(const struct device_node *np)
|
||||
{
|
||||
return of_property_read_bool(np, "poweroff-source");
|
||||
}
|
||||
|
||||
#endif /* _LINUX_OF_H */
|
||||
|
Loading…
Reference in New Issue
Block a user