Commit d7ab7302 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull MFD update from Samuel Ortiz:
 "For 3.10 we have a few new MFD drivers for:

   - The ChromeOS embedded controller which provides keyboard, battery
     and power management services.  This controller is accessible
     through i2c or SPI.

   - Silicon Laboratories 476x controller, providing access to their FM
     chipset and their audio codec.

   - Realtek's RTS5249, a memory stick, MMC and SD/SDIO PCI based
     reader.

   - Nokia's Tahvo power button and watchdog device.  This device is
     very similar to Retu and is thus supported by the same code base.

   - STMicroelectronics STMPE1801, a keyboard and GPIO controller
     supported by the stmpe driver.

   - ST-Ericsson AB8540 and AB8505 power management and voltage
     converter controllers through the existing ab8500 code.

  Some other drivers got cleaned up or improved.  In particular:

   - The Linaro/STE guys got the ab8500 driver in sync with their
     internal code through a series of optimizations, fixes and
     improvements.

   - The AS3711 and OMAP USB drivers now have DT support.

   - The arizona clock and interrupt handling code got improved.

   - The wm5102 register patch and boot mechanism also got improved."

* tag 'mfd-3.10-1' of git://git.kernel.org/pub/scm/linux/kernel/git/sameo/mfd-next: (104 commits)
  mfd: si476x: Don't use 0bNNN
  mfd: vexpress: Handle pending config transactions
  mfd: ab8500: Export ab8500_gpadc_sw_hw_convert properly
  mfd: si476x: Fix i2c warning
  mfd: si476x: Add header files and Kbuild plumbing
  mfd: si476x: Add chip properties handling code
  mfd: si476x: Add the bulk of the core driver
  mfd: si476x: Add commands abstraction layer
  mfd: rtsx: Support RTS5249
  mfd: retu: Add Tahvo support
  mfd: ucb1400: Pass ucb1400-gpio data through ac97 bus
  mfd: wm8994: Add some OF properties
  mfd: wm8994: Add device ID data to WM8994 OF device IDs
  input: Export matrix_keypad_parse_of_params()
  mfd: tps65090: Add compatible string for charger subnode
  mfd: db8500-prcmu: Support platform dependant device selection
  mfd: syscon: Fix warnings when printing resource_size_t
  of: Add stub of_get_parent for non-OF builds
  mfd: omap-usb-tll: Convert to devm_ioremap_resource()
  mfd: omap-usb-host: Convert to devm_ioremap_resource()
  ...
parents 01227a88 99f4c6b6
ChromeOS EC Keyboard
Google's ChromeOS EC Keyboard is a simple matrix keyboard implemented on
a separate EC (Embedded Controller) device. It provides a message for reading
key scans from the EC. These are then converted into keycodes for processing
by the kernel.
This binding is based on matrix-keymap.txt and extends/modifies it as follows:
Required properties:
- compatible: "google,cros-ec-keyb"
Optional properties:
- google,needs-ghost-filter: True to enable a ghost filter for the matrix
keyboard. This is recommended if the EC does not have its own logic or
hardware for this.
Example:
cros-ec-keyb {
compatible = "google,cros-ec-keyb";
keypad,num-rows = <8>;
keypad,num-columns = <13>;
google,needs-ghost-filter;
/*
* Keymap entries take the form of 0xRRCCKKKK where
* RR=Row CC=Column KKKK=Key Code
* The values below are for a US keyboard layout and
* are taken from the Linux driver. Note that the
* 102ND key is not used for US keyboards.
*/
linux,keymap = <
/* CAPSLCK F1 B F10 */
0x0001003a 0x0002003b 0x00030030 0x00040044
/* N = R_ALT ESC */
0x00060031 0x0008000d 0x000a0064 0x01010001
/* F4 G F7 H */
0x0102003e 0x01030022 0x01040041 0x01060023
/* ' F9 BKSPACE L_CTRL */
0x01080028 0x01090043 0x010b000e 0x0200001d
/* TAB F3 T F6 */
0x0201000f 0x0202003d 0x02030014 0x02040040
/* ] Y 102ND [ */
0x0205001b 0x02060015 0x02070056 0x0208001a
/* F8 GRAVE F2 5 */
0x02090042 0x03010029 0x0302003c 0x03030006
/* F5 6 - \ */
0x0304003f 0x03060007 0x0308000c 0x030b002b
/* R_CTRL A D F */
0x04000061 0x0401001e 0x04020020 0x04030021
/* S K J ; */
0x0404001f 0x04050025 0x04060024 0x04080027
/* L ENTER Z C */
0x04090026 0x040b001c 0x0501002c 0x0502002e
/* V X , M */
0x0503002f 0x0504002d 0x05050033 0x05060032
/* L_SHIFT / . SPACE */
0x0507002a 0x05080035 0x05090034 0x050B0039
/* 1 3 4 2 */
0x06010002 0x06020004 0x06030005 0x06040003
/* 8 7 0 9 */
0x06050009 0x06060008 0x0608000b 0x0609000a
/* L_ALT DOWN RIGHT Q */
0x060a0038 0x060b006c 0x060c006a 0x07010010
/* E R W I */
0x07020012 0x07030013 0x07040011 0x07050017
/* U R_SHIFT P O */
0x07060016 0x07070036 0x07080019 0x07090018
/* UP LEFT */
0x070b0067 0x070c0069>;
};
AS3711 is an I2C PMIC from Austria MicroSystems with multiple DCDC and LDO power
supplies, a battery charger and an RTC. So far only bindings for the two stepup
DCDC converters are defined. Other DCDC and LDO supplies are configured, using
standard regulator properties, they must belong to a sub-node, called
"regulators" and be called "sd1" to "sd4" and "ldo1" to "ldo8." Stepup converter
configuration should be placed in a subnode, called "backlight."
Compulsory properties:
- compatible : must be "ams,as3711"
- reg : specifies the I2C address
To use the SU1 converter as a backlight source the following two properties must
be provided:
- su1-dev : framebuffer phandle
- su1-max-uA : maximum current
To use the SU2 converter as a backlight source the following two properties must
be provided:
- su2-dev : framebuffer phandle
- su1-max-uA : maximum current
Additionally one of these properties must be provided to select the type of
feedback used:
- su2-feedback-voltage : voltage feedback is used
- su2-feedback-curr1 : CURR1 input used for current feedback
- su2-feedback-curr2 : CURR2 input used for current feedback
- su2-feedback-curr3 : CURR3 input used for current feedback
- su2-feedback-curr-auto: automatic current feedback selection
and one of these to select the over-voltage protection pin
- su2-fbprot-lx-sd4 : LX_SD4 is used for over-voltage protection
- su2-fbprot-gpio2 : GPIO2 is used for over-voltage protection
- su2-fbprot-gpio3 : GPIO3 is used for over-voltage protection
- su2-fbprot-gpio4 : GPIO4 is used for over-voltage protection
If "su2-feedback-curr-auto" is selected, one or more of the following properties
have to be specified:
- su2-auto-curr1 : use CURR1 input for current feedback
- su2-auto-curr2 : use CURR2 input for current feedback
- su2-auto-curr3 : use CURR3 input for current feedback
Example:
as3711@40 {
compatible = "ams,as3711";
reg = <0x40>;
regulators {
sd4 {
regulator-name = "1.215V";
regulator-min-microvolt = <1215000>;
regulator-max-microvolt = <1235000>;
};
ldo2 {
regulator-name = "2.8V CPU";
regulator-min-microvolt = <2800000>;
regulator-max-microvolt = <2800000>;
regulator-always-on;
regulator-boot-on;
};
};
backlight {
compatible = "ams,as3711-bl";
su2-dev = <&lcdc>;
su2-max-uA = <36000>;
su2-feedback-curr-auto;
su2-fbprot-gpio4;
su2-auto-curr1;
su2-auto-curr2;
su2-auto-curr3;
};
};
ChromeOS Embedded Controller
Google's ChromeOS EC is a Cortex-M device which talks to the AP and
implements various function such as keyboard and battery charging.
The EC can be connect through various means (I2C, SPI, LPC) and the
compatible string used depends on the inteface. Each connection method has
its own driver which connects to the top level interface-agnostic EC driver.
Other Linux driver (such as cros-ec-keyb for the matrix keyboard) connect to
the top-level driver.
Required properties (I2C):
- compatible: "google,cros-ec-i2c"
- reg: I2C slave address
Required properties (SPI):
- compatible: "google,cros-ec-spi"
- reg: SPI chip select
Required properties (LPC):
- compatible: "google,cros-ec-lpc"
- reg: List of (IO address, size) pairs defining the interface uses
Example for I2C:
i2c@12CA0000 {
cros-ec@1e {
reg = <0x1e>;
compatible = "google,cros-ec-i2c";
interrupts = <14 0>;
interrupt-parent = <&wakeup_eint>;
wakeup-source;
};
Example for SPI:
spi@131b0000 {
ec@0 {
compatible = "google,cros-ec-spi";
reg = <0x0>;
interrupts = <14 0>;
interrupt-parent = <&wakeup_eint>;
wakeup-source;
spi-max-frequency = <5000000>;
controller-data {
cs-gpio = <&gpf0 3 4 3 0>;
samsung,spi-cs;
samsung,spi-feedback-delay = <2>;
};
};
};
Example for LPC is not supplied as it is not yet implemented.
OMAP HS USB Host
Required properties:
- compatible: should be "ti,usbhs-host"
- reg: should contain one register range i.e. start and length
- ti,hwmods: must contain "usb_host_hs"
Optional properties:
- num-ports: number of USB ports. Usually this is automatically detected
from the IP's revision register but can be overridden by specifying
this property. A maximum of 3 ports are supported at the moment.
- portN-mode: String specifying the port mode for port N, where N can be
from 1 to 3. If the port mode is not specified, that port is treated
as unused. When specified, it must be one of the following.
"ehci-phy",
"ehci-tll",
"ehci-hsic",
"ohci-phy-6pin-datse0",
"ohci-phy-6pin-dpdm",
"ohci-phy-3pin-datse0",
"ohci-phy-4pin-dpdm",
"ohci-tll-6pin-datse0",
"ohci-tll-6pin-dpdm",
"ohci-tll-3pin-datse0",
"ohci-tll-4pin-dpdm",
"ohci-tll-2pin-datse0",
"ohci-tll-2pin-dpdm",
- single-ulpi-bypass: Must be present if the controller contains a single
ULPI bypass control bit. e.g. OMAP3 silicon <= ES2.1
Required properties if child node exists:
- #address-cells: Must be 1
- #size-cells: Must be 1
- ranges: must be present
Properties for children:
The OMAP HS USB Host subsystem contains EHCI and OHCI controllers.
See Documentation/devicetree/bindings/usb/omap-ehci.txt and
omap3-ohci.txt
Example for OMAP4:
usbhshost: usbhshost@4a064000 {
compatible = "ti,usbhs-host";
reg = <0x4a064000 0x800>;
ti,hwmods = "usb_host_hs";
#address-cells = <1>;
#size-cells = <1>;
ranges;
usbhsohci: ohci@4a064800 {
compatible = "ti,ohci-omap3", "usb-ohci";
reg = <0x4a064800 0x400>;
interrupt-parent = <&gic>;
interrupts = <0 76 0x4>;
};
usbhsehci: ehci@4a064c00 {
compatible = "ti,ehci-omap", "usb-ehci";
reg = <0x4a064c00 0x400>;
interrupt-parent = <&gic>;
interrupts = <0 77 0x4>;
};
};
&usbhshost {
port1-mode = "ehci-phy";
port2-mode = "ehci-tll";
port3-mode = "ehci-phy";
};
&usbhsehci {
phys = <&hsusb1_phy 0 &hsusb3_phy>;
};
OMAP HS USB Host TLL (Transceiver-Less Interface)
Required properties:
- compatible : should be "ti,usbhs-tll"
- reg : should contain one register range i.e. start and length
- interrupts : should contain the TLL module's interrupt
- ti,hwmod : must contain "usb_tll_hs"
Example:
usbhstll: usbhstll@4a062000 {
compatible = "ti,usbhs-tll";
reg = <0x4a062000 0x1000>;
interrupts = <78>;
ti,hwmods = "usb_tll_hs";
};
...@@ -5,14 +5,70 @@ on the board). ...@@ -5,14 +5,70 @@ on the board).
Required properties: Required properties:
- compatible : "wlf,wm1811", "wlf,wm8994", "wlf,wm8958" - compatible : One of "wlf,wm1811", "wlf,wm8994" or "wlf,wm8958".
- reg : the I2C address of the device for I2C, the chip select - reg : the I2C address of the device for I2C, the chip select
number for SPI. number for SPI.
- gpio-controller : Indicates this device is a GPIO controller.
- #gpio-cells : Must be 2. The first cell is the pin number and the
second cell is used to specify optional parameters (currently unused).
- AVDD2-supply, DBVDD1-supply, DBVDD2-supply, DBVDD3-supply, CPVDD-supply,
SPKVDD1-supply, SPKVDD2-supply : power supplies for the device, as covered
in Documentation/devicetree/bindings/regulator/regulator.txt
Optional properties:
- interrupts : The interrupt line the IRQ signal for the device is
connected to. This is optional, if it is not connected then none
of the interrupt related properties should be specified.
- interrupt-controller : These devices contain interrupt controllers
and may provide interrupt services to other devices if they have an
interrupt line connected.
- interrupt-parent : The parent interrupt controller.
- #interrupt-cells: the number of cells to describe an IRQ, this should be 2.
The first cell is the IRQ number.
The second cell is the flags, encoded as the trigger masks from
Documentation/devicetree/bindings/interrupts.txt
- wlf,gpio-cfg : A list of GPIO configuration register values. If absent,
no configuration of these registers is performed. If any value is
over 0xffff then the register will be left as default. If present 11
values must be supplied.
- wlf,micbias-cfg : Two MICBIAS register values for WM1811 or
WM8958. If absent the register defaults will be used.
- wlf,ldo1ena : GPIO specifier for control of LDO1ENA input to device.
- wlf,ldo2ena : GPIO specifier for control of LDO2ENA input to device.
- wlf,lineout1-se : If present LINEOUT1 is in single ended mode.
- wlf,lineout2-se : If present LINEOUT2 is in single ended mode.
- wlf,lineout1-feedback : If present LINEOUT1 has common mode feedback
connected.
- wlf,lineout2-feedback : If present LINEOUT2 has common mode feedback
connected.
- wlf,ldoena-always-driven : If present LDOENA is always driven.
Example: Example:
codec: wm8994@1a { codec: wm8994@1a {
compatible = "wlf,wm8994"; compatible = "wlf,wm8994";
reg = <0x1a>; reg = <0x1a>;
gpio-controller;
#gpio-cells = <2>;
lineout1-se;
AVDD2-supply = <&regulator>;
CPVDD-supply = <&regulator>;
DBVDD1-supply = <&regulator>;
DBVDD2-supply = <&regulator>;
DBVDD3-supply = <&regulator>;
SPKVDD1-supply = <&regulator>;
SPKVDD2-supply = <&regulator>;
}; };
...@@ -466,8 +466,6 @@ config MACH_MX31ADS_WM1133_EV1 ...@@ -466,8 +466,6 @@ config MACH_MX31ADS_WM1133_EV1
depends on MACH_MX31ADS depends on MACH_MX31ADS
depends on MFD_WM8350_I2C depends on MFD_WM8350_I2C
depends on REGULATOR_WM8350 = y depends on REGULATOR_WM8350 = y
select MFD_WM8350_CONFIG_MODE_0
select MFD_WM8352_CONFIG_MODE_0
help help
Include support for the Wolfson Microelectronics 1133-EV1 PMU Include support for the Wolfson Microelectronics 1133-EV1 PMU
and audio module for the MX31ADS platform. and audio module for the MX31ADS platform.
......
...@@ -200,10 +200,7 @@ endchoice ...@@ -200,10 +200,7 @@ endchoice
config SMDK6410_WM1190_EV1 config SMDK6410_WM1190_EV1
bool "Support Wolfson Microelectronics 1190-EV1 PMIC card" bool "Support Wolfson Microelectronics 1190-EV1 PMIC card"
depends on MACH_SMDK6410 depends on MACH_SMDK6410
select MFD_WM8350_CONFIG_MODE_0
select MFD_WM8350_CONFIG_MODE_3
select MFD_WM8350_I2C select MFD_WM8350_I2C
select MFD_WM8352_CONFIG_MODE_0
select REGULATOR select REGULATOR
select REGULATOR_WM8350 select REGULATOR_WM8350
select SAMSUNG_GPIO_EXTRA64 select SAMSUNG_GPIO_EXTRA64
......
...@@ -208,7 +208,7 @@ static const struct i2c_board_info wm1277_devs[] = { ...@@ -208,7 +208,7 @@ static const struct i2c_board_info wm1277_devs[] = {
static struct arizona_pdata wm5102_reva_pdata = { static struct arizona_pdata wm5102_reva_pdata = {
.ldoena = S3C64XX_GPN(7), .ldoena = S3C64XX_GPN(7),
.gpio_base = CODEC_GPIO_BASE, .gpio_base = CODEC_GPIO_BASE,
.irq_active_high = true, .irq_flags = IRQF_TRIGGER_HIGH,
.micd_pol_gpio = CODEC_GPIO_BASE + 4, .micd_pol_gpio = CODEC_GPIO_BASE + 4,
.micd_rate = 6, .micd_rate = 6,
.gpio_defaults = { .gpio_defaults = {
...@@ -238,7 +238,7 @@ static struct spi_board_info wm5102_reva_spi_devs[] = { ...@@ -238,7 +238,7 @@ static struct spi_board_info wm5102_reva_spi_devs[] = {
static struct arizona_pdata wm5102_pdata = { static struct arizona_pdata wm5102_pdata = {
.ldoena = S3C64XX_GPN(7), .ldoena = S3C64XX_GPN(7),
.gpio_base = CODEC_GPIO_BASE, .gpio_base = CODEC_GPIO_BASE,
.irq_active_high = true, .irq_flags = IRQF_TRIGGER_HIGH,
.micd_pol_gpio = CODEC_GPIO_BASE + 2, .micd_pol_gpio = CODEC_GPIO_BASE + 2,
.gpio_defaults = { .gpio_defaults = {
[2] = 0x10000, /* AIF3TXLRCLK */ [2] = 0x10000, /* AIF3TXLRCLK */
......
...@@ -12,8 +12,6 @@ ...@@ -12,8 +12,6 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/ucb1400.h> #include <linux/ucb1400.h>
struct ucb1400_gpio_data *ucbdata;
static int ucb1400_gpio_dir_in(struct gpio_chip *gc, unsigned off) static int ucb1400_gpio_dir_in(struct gpio_chip *gc, unsigned off)
{ {
struct ucb1400_gpio *gpio; struct ucb1400_gpio *gpio;
...@@ -50,7 +48,7 @@ static int ucb1400_gpio_probe(struct platform_device *dev) ...@@ -50,7 +48,7 @@ static int ucb1400_gpio_probe(struct platform_device *dev)
struct ucb1400_gpio *ucb = dev->dev.platform_data; struct ucb1400_gpio *ucb = dev->dev.platform_data;
int err = 0; int err = 0;
if (!(ucbdata && ucbdata->gpio_offset)) { if (!(ucb && ucb->gpio_offset)) {
err = -EINVAL; err = -EINVAL;
goto err; goto err;
} }
...@@ -58,7 +56,7 @@ static int ucb1400_gpio_probe(struct platform_device *dev) ...@@ -58,7 +56,7 @@ static int ucb1400_gpio_probe(struct platform_device *dev)
platform_set_drvdata(dev, ucb); platform_set_drvdata(dev, ucb);
ucb->gc.label = "ucb1400_gpio"; ucb->gc.label = "ucb1400_gpio";
ucb->gc.base = ucbdata->gpio_offset; ucb->gc.base = ucb->gpio_offset;
ucb->gc.ngpio = 10; ucb->gc.ngpio = 10;
ucb->gc.owner = THIS_MODULE; ucb->gc.owner = THIS_MODULE;
...@@ -72,8 +70,8 @@ static int ucb1400_gpio_probe(struct platform_device *dev) ...@@ -72,8 +70,8 @@ static int ucb1400_gpio_probe(struct platform_device *dev)
if (err) if (err)
goto err; goto err;
if (ucbdata && ucbdata->gpio_setup) if (ucb && ucb->gpio_setup)
err = ucbdata->gpio_setup(&dev->dev, ucb->gc.ngpio); err = ucb->gpio_setup(&dev->dev, ucb->gc.ngpio);
err: err:
return err; return err;
...@@ -85,8 +83,8 @@ static int ucb1400_gpio_remove(struct platform_device *dev) ...@@ -85,8 +83,8 @@ static int ucb1400_gpio_remove(struct platform_device *dev)
int err = 0; int err = 0;
struct ucb1400_gpio *ucb = platform_get_drvdata(dev); struct ucb1400_gpio *ucb = platform_get_drvdata(dev);
if (ucbdata && ucbdata->gpio_teardown) { if (ucb && ucb->gpio_teardown) {
err = ucbdata->gpio_teardown(&dev->dev, ucb->gc.ngpio); err = ucb->gpio_teardown(&dev->dev, ucb->gc.ngpio);
if (err) if (err)
return err; return err;
} }
...@@ -103,11 +101,6 @@ static struct platform_driver ucb1400_gpio_driver = { ...@@ -103,11 +101,6 @@ static struct platform_driver ucb1400_gpio_driver = {
}, },
}; };
void __init ucb1400_gpio_set_data(struct ucb1400_gpio_data *data)
{
ucbdata = data;
}
module_platform_driver(ucb1400_gpio_driver); module_platform_driver(ucb1400_gpio_driver);
MODULE_DESCRIPTION("Philips UCB1400 GPIO driver"); MODULE_DESCRIPTION("Philips UCB1400 GPIO driver");
......
...@@ -628,4 +628,16 @@ config KEYBOARD_W90P910 ...@@ -628,4 +628,16 @@ config KEYBOARD_W90P910
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called w90p910_keypad. module will be called w90p910_keypad.
config KEYBOARD_CROS_EC
tristate "ChromeOS EC keyboard"
select INPUT_MATRIXKMAP
depends on MFD_CROS_EC
help
Say Y here to enable the matrix keyboard used by ChromeOS devices
and implemented on the ChromeOS EC. You must enable one bus option
(MFD_CROS_EC_I2C or MFD_CROS_EC_SPI) to use this.
To compile this driver as a module, choose M here: the
module will be called cros_ec_keyb.
endif endif
...@@ -11,6 +11,7 @@ obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o ...@@ -11,6 +11,7 @@ obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o
obj-$(CONFIG_KEYBOARD_ATARI) += atakbd.o obj-$(CONFIG_KEYBOARD_ATARI) += atakbd.o
obj-$(CONFIG_KEYBOARD_ATKBD) += atkbd.o obj-$(CONFIG_KEYBOARD_ATKBD) += atkbd.o
obj-$(CONFIG_KEYBOARD_BFIN) += bf54x-keys.o obj-$(CONFIG_KEYBOARD_BFIN) += bf54x-keys.o
obj-$(CONFIG_KEYBOARD_CROS_EC) += cros_ec_keyb.o
obj-$(CONFIG_KEYBOARD_DAVINCI) += davinci_keyscan.o obj-$(CONFIG_KEYBOARD_DAVINCI) += davinci_keyscan.o
obj-$(CONFIG_KEYBOARD_EP93XX) += ep93xx_keypad.o obj-$(CONFIG_KEYBOARD_EP93XX) += ep93xx_keypad.o
obj-$(CONFIG_KEYBOARD_GOLDFISH_EVENTS) += goldfish_events.o obj-$(CONFIG_KEYBOARD_GOLDFISH_EVENTS) += goldfish_events.o
......
/*
* ChromeOS EC keyboard driver
*
* Copyright (C) 2012 Google, Inc
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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.
*
* This driver uses the Chrome OS EC byte-level message-based protocol for
* communicating the keyboard state (which keys are pressed) from a keyboard EC
* to the AP over some bus (such as i2c, lpc, spi). The EC does debouncing,
* but everything else (including deghosting) is done here. The main
* motivation for this is to keep the EC firmware as simple as possible, since
* it cannot be easily upgraded and EC flash/IRAM space is relatively
* expensive.
*/
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/kernel.h>
#include <linux/notifier.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/input/matrix_keypad.h>
#include <linux/mfd/cros_ec.h>
#include <linux/mfd/cros_ec_commands.h>
/*
* @rows: Number of rows in the keypad
* @cols: Number of columns in the keypad
* @row_shift: log2 or number of rows, rounded up
* @keymap_data: Matrix keymap data used to convert to keyscan values
* @ghost_filter: true to enable the matrix key-ghosting filter
* @dev: Device pointer
* @idev: Input device
* @ec: Top level ChromeOS device to use to talk to EC
* @event_notifier: interrupt event notifier for transport devices
*/
struct cros_ec_keyb {
unsigned int rows;
unsigned int cols;
int row_shift;
const struct matrix_keymap_data *keymap_data;
bool ghost_filter;
struct device *dev;
struct input_dev *idev;
struct cros_ec_device *ec;
struct notifier_block notifier;
};
static bool cros_ec_keyb_row_has_ghosting(struct cros_ec_keyb *ckdev,
uint8_t *buf, int row)
{
int pressed_in_row = 0;
int row_has_teeth = 0;
int col, mask;
mask = 1 << row;
for (col = 0; col < ckdev->cols; col++) {
if (buf[col] & mask) {
pressed_in_row++;
row_has_teeth |= buf[col] & ~mask;
if (pressed_in_row > 1 && row_has_teeth) {
/* ghosting */
dev_dbg(ckdev->dev,
"ghost found at: r%d c%d, pressed %d, teeth 0x%x\n",
row, col, pressed_in_row,
row_has_teeth);
return true;
}
}
}
return false;
}
/*
* Returns true when there is at least one combination of pressed keys that
* results in ghosting.
*/
static bool cros_ec_keyb_has_ghosting(struct cros_ec_keyb *ckdev, uint8_t *buf)
{
int row;
/*
* Ghosting happens if for any pressed key X there are other keys
* pressed both in the same row and column of X as, for instance,
* in the following diagram:
*
* . . Y . g .
* . . . . . .
* . . . . . .
* . . X . Z .
*
* In this case only X, Y, and Z are pressed, but g appears to be
* pressed too (see Wikipedia).
*
* We can detect ghosting in a single pass (*) over the keyboard state
* by maintaining two arrays. pressed_in_row counts how many pressed
* keys we have found in a row. row_has_teeth is true if any of the
* pressed keys for this row has other pressed keys in its column. If
* at any point of the scan we find that a row has multiple pressed
* keys, and at least one of them is at the intersection with a column
* with multiple pressed keys, we're sure there is ghosting.
* Conversely, if there is ghosting, we will detect such situation for
* at least one key during the pass.
*
* (*) This looks linear in the number of keys, but it's not. We can
* cheat because the number of rows is small.
*/
for (row = 0; row < ckdev->rows; row++)
if (cros_ec_keyb_row_has_ghosting(ckdev, buf, row))
return true;
return false;
}
/*
* Compares the new keyboard state to the old one and produces key
* press/release events accordingly. The keyboard state is 13 bytes (one byte
* per column)
*/
static void cros_ec_keyb_process(struct cros_ec_keyb *ckdev,
uint8_t *kb_state, int len)
{
struct input_dev *idev = ckdev->idev;
int col, row;
int new_state;
int num_cols;
num_cols = len;
if (ckdev->ghost_filter && cros_ec_keyb_has_ghosting(ckdev, kb_state)) {
/*
* Simple-minded solution: ignore this state. The obvious
* improvement is to only ignore changes to keys involved in
* the ghosting, but process the other changes.
*/
dev_dbg(ckdev->dev, "ghosting found\n");
return;
}
for (col = 0; col < ckdev->cols; col++) {
for (row = 0; row < ckdev->rows; row++) {
int pos = MATRIX_SCAN_CODE(row, col, ckdev->row_shift);
const unsigned short *keycodes = idev->keycode;
int code;
code = keycodes[pos];
new_state = kb_state[col] & (1 << row);
if (!!new_state != test_bit(code, idev->key)) {
dev_dbg(ckdev->dev,
"changed: [r%d c%d]: byte %02x\n",
row, col, new_state);
input_report_key(idev, code, new_state);
}
}
}
input_sync(ckdev->idev);
}
static int cros_ec_keyb_open(struct input_dev *dev)
{
struct cros_ec_keyb *ckdev = input_get_drvdata(dev);
return blocking_notifier_chain_register(&ckdev->ec->event_notifier,
&ckdev->notifier);
}
static void cros_ec_keyb_close(struct input_dev *dev)
{
struct cros_ec_keyb *ckdev = input_get_drvdata(dev);
blocking_notifier_chain_unregister(&ckdev->ec->event_notifier,
&ckdev->notifier);
}
static int cros_ec_keyb_get_state(struct cros_ec_keyb *ckdev, uint8_t *kb_state)
{
return ckdev->ec->command_recv(ckdev->ec, EC_CMD_MKBP_STATE,
kb_state, ckdev->cols);
}
static int cros_ec_keyb_work(struct notifier_block *nb,
unsigned long state, void *_notify)
{
int ret;
struct cros_ec_keyb *ckdev = container_of(nb, struct cros_ec_keyb,
notifier);
uint8_t kb_state[ckdev->cols];
ret = cros_ec_keyb_get_state(ckdev, kb_state);
if (ret >= 0)
cros_ec_keyb_process(ckdev, kb_state, ret);
return NOTIFY_DONE;
}
/* Clear any keys in the buffer */
static void cros_ec_keyb_clear_keyboard(struct cros_ec_keyb *ckdev)
{
uint8_t old_state[ckdev->cols];
uint8_t new_state[ckdev->cols];
unsigned long duration;
int i, ret;
/*
* Keep reading until we see that the scan state does not change.
* That indicates that we are done.
*
* Assume that the EC keyscan buffer is at most 32 deep.
*/
duration = jiffies;
ret = cros_ec_keyb_get_state(ckdev, new_state);
for (i = 1; !ret && i < 32; i++) {
memcpy(old_state, new_state, sizeof(old_state));
ret = cros_ec_keyb_get_state(ckdev, new_state);
if (0 == memcmp(old_state, new_state, sizeof(old_state)))
break;
}
duration = jiffies - duration;
dev_info(ckdev->dev, "Discarded %d keyscan(s) in %dus\n", i,
jiffies_to_usecs(duration));
}
static int cros_ec_keyb_probe(struct platform_device *pdev)
{
struct cros_ec_device *ec = dev_get_drvdata(pdev->dev.parent);
struct device *dev = ec->dev;
struct cros_ec_keyb *ckdev;
struct input_dev *idev;
struct device_node *np;
int err;
np = pdev->dev.of_node;
if (!np)
return -ENODEV;
ckdev = devm_kzalloc(&pdev->dev, sizeof(*ckdev), GFP_KERNEL);
if (!ckdev)
return -ENOMEM;
err = matrix_keypad_parse_of_params(&pdev->dev, &ckdev->rows,
&ckdev->cols);
if (err)
return err;
idev = devm_input_allocate_device(&pdev->dev);
if (!idev)
return -ENOMEM;
ckdev->ec = ec;
ckdev->notifier.notifier_call = cros_ec_keyb_work;
ckdev->dev = dev;
dev_set_drvdata(&pdev->dev, ckdev);
idev->name = ec->ec_name;
idev->phys = ec->phys_name;
__set_bit(EV_REP, idev->evbit);
idev->id.bustype = BUS_VIRTUAL;
idev->id.version = 1;
idev->id.product = 0;
idev->dev.parent = &pdev->dev;
idev->open = cros_ec_keyb_open;
idev->close = cros_ec_keyb_close;
ckdev->ghost_filter = of_property_read_bool(np,
"google,needs-ghost-filter");
err = matrix_keypad_build_keymap(NULL, NULL, ckdev->rows, ckdev->cols,
NULL, idev);
if (err) {
dev_err(dev, "cannot build key matrix\n");
return err;
}
ckdev->row_shift = get_count_order(ckdev->cols);
input_set_capability(idev, EV_MSC, MSC_SCAN);
input_set_drvdata(idev, ckdev);
ckdev->idev = idev;
err = input_register_device(ckdev->idev);
if (err) {
dev_err(dev, "cannot register input device\n");
return err;
}
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int cros_ec_keyb_resume(struct device *dev)
{
struct cros_ec_keyb *ckdev = dev_get_drvdata(dev);
/*
* When the EC is not a wake source, then it could not have caused the
* resume, so we clear the EC's key scan buffer. If the EC was a
* wake source (e.g. the lid is open and the user might press a key to
* wake) then the key scan buffer should be preserved.
*/
if (ckdev->ec->was_wake_device)
cros_ec_keyb_clear_keyboard(ckdev);
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(cros_ec_keyb_pm_ops, NULL, cros_ec_keyb_resume);
static struct platform_driver cros_ec_keyb_driver = {
.probe = cros_ec_keyb_probe,
.driver = {
.name = "cros-ec-keyb",
.pm = &cros_ec_keyb_pm_ops,
},
};
module_platform_driver(cros_ec_keyb_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("ChromeOS EC keyboard driver");
MODULE_ALIAS("platform:cros-ec-keyb");
...@@ -144,12 +144,13 @@ static int lpc32xx_parse_dt(struct device *dev, ...@@ -144,12 +144,13 @@ static int lpc32xx_parse_dt(struct device *dev,
{ {
struct device_node *np = dev->of_node; struct device_node *np = dev->of_node;
u32 rows = 0, columns = 0; u32 rows = 0, columns = 0;
int err;
of_property_read_u32(np, "keypad,num-rows", &rows); err = matrix_keypad_parse_of_params(dev, &rows, &columns);
of_property_read_u32(np, "keypad,num-columns", &columns); if (err)
if (!rows || rows != columns) { return err;
dev_err(dev, if (rows != columns) {
"rows and columns must be specified and be equal!\n"); dev_err(dev, "rows and columns must be equal!\n");
return -EINVAL; return -EINVAL;
} }
......
...@@ -215,18 +215,12 @@ static int omap4_keypad_parse_dt(struct device *dev, ...@@ -215,18 +215,12 @@ static int omap4_keypad_parse_dt(struct device *dev,
struct omap4_keypad *keypad_data) struct omap4_keypad *keypad_data)
{ {
struct device_node *np = dev->of_node; struct device_node *np = dev->of_node;
int err;
if (!np) { err = matrix_keypad_parse_of_params(dev, &keypad_data->rows,
dev_err(dev, "missing DT data"); &keypad_data->cols);
return -EINVAL; if (err)
} return err;
of_property_read_u32(np, "keypad,num-rows", &keypad_data->rows);
of_property_read_u32(np, "keypad,num-columns", &keypad_data->cols);
if (!keypad_data->rows || !keypad_data->cols) {
dev_err(dev, "number of keypad rows/columns not specified\n");
return -EINVAL;
}
if (of_get_property(np, "linux,input-no-autorepeat", NULL)) if (of_get_property(np, "linux,input-no-autorepeat", NULL))
keypad_data->no_autorepeat = true; keypad_data->no_autorepeat = true;
......
...@@ -288,8 +288,11 @@ static int tca8418_keypad_probe(struct i2c_client *client, ...@@ -288,8 +288,11 @@ static int tca8418_keypad_probe(struct i2c_client *client,
irq_is_gpio = pdata->irq_is_gpio; irq_is_gpio = pdata->irq_is_gpio;
} else { } else {
struct device_node *np = dev->of_node; struct device_node *np = dev->of_node;
of_property_read_u32(np, "keypad,num-rows", &rows); int err;
of_property_read_u32(np, "keypad,num-columns", &cols);
err = matrix_keypad_parse_of_params(dev, &rows, &cols);
if (err)
return err;
rep = of_property_read_bool(np, "keypad,autorepeat"); rep = of_property_read_bool(np, "keypad,autorepeat");
} }
......
...@@ -50,6 +50,26 @@ static bool matrix_keypad_map_key(struct input_dev *input_dev, ...@@ -50,6 +50,26 @@ static bool matrix_keypad_map_key(struct input_dev *input_dev,
} }
#ifdef CONFIG_OF #ifdef CONFIG_OF
int matrix_keypad_parse_of_params(struct device *dev,
unsigned int *rows, unsigned int *cols)
{
struct device_node *np = dev->of_node;
if (!np) {
dev_err(dev, "missing DT data");
return -EINVAL;
}
of_property_read_u32(np, "keypad,num-rows", rows);
of_property_read_u32(np, "keypad,num-columns", cols);
if (!*rows || !*cols) {
dev_err(dev, "number of keypad rows/columns not specified\n");
return -EINVAL;
}
return 0;
}
EXPORT_SYMBOL_GPL(matrix_keypad_parse_of_params);
static int matrix_keypad_parse_of_keymap(const char *propname, static int matrix_keypad_parse_of_keymap(const char *propname,
unsigned int rows, unsigned int cols, unsigned int rows, unsigned int cols,
struct input_dev *input_dev) struct input_dev *input_dev)
......
...@@ -1144,17 +1144,15 @@ static int pm860x_probe(struct i2c_client *client, ...@@ -1144,17 +1144,15 @@ static int pm860x_probe(struct i2c_client *client,
return -ENOMEM; return -ENOMEM;
ret = pm860x_dt_init(node, &client->dev, pdata); ret = pm860x_dt_init(node, &client->dev, pdata);
if (ret) if (ret)
goto err; return ret;
} else if (!pdata) { } else if (!pdata) {
pr_info("No platform data in %s!\n", __func__); pr_info("No platform data in %s!\n", __func__);
return -EINVAL; return -EINVAL;
} }
chip = kzalloc(sizeof(struct pm860x_chip), GFP_KERNEL); chip = kzalloc(sizeof(struct pm860x_chip), GFP_KERNEL);
if (chip == NULL) { if (chip == NULL)
ret = -ENOMEM; return -ENOMEM;
goto err;
}
chip->id = verify_addr(client); chip->id = verify_addr(client);
chip->regmap = regmap_init_i2c(client, &pm860x_regmap_config); chip->regmap = regmap_init_i2c(client, &pm860x_regmap_config);
...@@ -1194,10 +1192,6 @@ static int pm860x_probe(struct i2c_client *client, ...@@ -1194,10 +1192,6 @@ static int pm860x_probe(struct i2c_client *client,
pm860x_device_init(chip, pdata); pm860x_device_init(chip, pdata);
return 0; return 0;
err:
if (node)
devm_kfree(&client->dev, pdata);
return ret;
} }
static int pm860x_remove(struct i2c_client *client) static int pm860x_remove(struct i2c_client *client)
......
This diff is collapsed.
...@@ -8,8 +8,11 @@ obj-$(CONFIG_MFD_88PM800) += 88pm800.o 88pm80x.o ...@@ -8,8 +8,11 @@ obj-$(CONFIG_MFD_88PM800) += 88pm800.o 88pm80x.o
obj-$(CONFIG_MFD_88PM805) += 88pm805.o 88pm80x.o obj-$(CONFIG_MFD_88PM805) += 88pm805.o 88pm80x.o
obj-$(CONFIG_MFD_SM501) += sm501.o obj-$(CONFIG_MFD_SM501) += sm501.o
obj-$(CONFIG_MFD_ASIC3) += asic3.o tmio_core.o obj-$(CONFIG_MFD_ASIC3) += asic3.o tmio_core.o
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 rtsx_pci-objs := rtsx_pcr.o rts5209.o rts5229.o rtl8411.o rts5227.o rts5249.o
obj-$(CONFIG_MFD_RTSX_PCI) += rtsx_pci.o obj-$(CONFIG_MFD_RTSX_PCI) += rtsx_pci.o
obj-$(CONFIG_HTC_EGPIO) += htc-egpio.o obj-$(CONFIG_HTC_EGPIO) += htc-egpio.o
...@@ -131,6 +134,10 @@ obj-$(CONFIG_MFD_JZ4740_ADC) += jz4740-adc.o ...@@ -131,6 +134,10 @@ obj-$(CONFIG_MFD_JZ4740_ADC) += jz4740-adc.o
obj-$(CONFIG_MFD_TPS6586X) += tps6586x.o obj-$(CONFIG_MFD_TPS6586X) += tps6586x.o
obj-$(CONFIG_MFD_VX855) += vx855.o obj-$(CONFIG_MFD_VX855) += vx855.o
obj-$(CONFIG_MFD_WL1273_CORE) += wl1273-core.o obj-$(CONFIG_MFD_WL1273_CORE) += wl1273-core.o
si476x-core-y := si476x-cmd.o si476x-prop.o si476x-i2c.o
obj-$(CONFIG_MFD_SI476X_CORE) += si476x-core.o
obj-$(CONFIG_MFD_CS5535) += cs5535-mfd.o obj-$(CONFIG_MFD_CS5535) += cs5535-mfd.o
obj-$(CONFIG_MFD_OMAP_USB_HOST) += omap-usb-host.o omap-usb-tll.o obj-$(CONFIG_MFD_OMAP_USB_HOST) += omap-usb-host.o omap-usb-tll.o
obj-$(CONFIG_MFD_PM8921_CORE) += pm8921-core.o obj-$(CONFIG_MFD_PM8921_CORE) += pm8921-core.o
......
...@@ -367,12 +367,12 @@ static int aat2870_i2c_probe(struct i2c_client *client, ...@@ -367,12 +367,12 @@ static int aat2870_i2c_probe(struct i2c_client *client,
int i, j; int i, j;
int ret = 0; int ret = 0;
aat2870 = kzalloc(sizeof(struct aat2870_data), GFP_KERNEL); aat2870 = devm_kzalloc(&client->dev, sizeof(struct aat2870_data),
GFP_KERNEL);
if (!aat2870) { if (!aat2870) {
dev_err(&client->dev, dev_err(&client->dev,
"Failed to allocate memory for aat2870\n"); "Failed to allocate memory for aat2870\n");
ret = -ENOMEM; return -ENOMEM;
goto out;
} }
aat2870->dev = &client->dev; aat2870->dev = &client->dev;
...@@ -400,12 +400,12 @@ static int aat2870_i2c_probe(struct i2c_client *client, ...@@ -400,12 +400,12 @@ static int aat2870_i2c_probe(struct i2c_client *client,
aat2870->init(aat2870); aat2870->init(aat2870);
if (aat2870->en_pin >= 0) { if (aat2870->en_pin >= 0) {
ret = gpio_request_one(aat2870->en_pin, GPIOF_OUT_INIT_HIGH, ret = devm_gpio_request_one(&client->dev, aat2870->en_pin,
"aat2870-en"); GPIOF_OUT_INIT_HIGH, "aat2870-en");
if (ret < 0) { if (ret < 0) {
dev_err(&client->dev, dev_err(&client->dev,
"Failed to request GPIO %d\n", aat2870->en_pin); "Failed to request GPIO %d\n", aat2870->en_pin);
goto out_kfree; return ret;
} }
} }
...@@ -436,11 +436,6 @@ static int aat2870_i2c_probe(struct i2c_client *client, ...@@ -436,11 +436,6 @@ static int aat2870_i2c_probe(struct i2c_client *client,
out_disable: out_disable:
aat2870_disable(aat2870); aat2870_disable(aat2870);
if (aat2870->en_pin >= 0)
gpio_free(aat2870->en_pin);
out_kfree:
kfree(aat2870);
out:
return ret; return ret;
} }
...@@ -452,11 +447,8 @@ static int aat2870_i2c_remove(struct i2c_client *client) ...@@ -452,11 +447,8 @@ static int aat2870_i2c_remove(struct i2c_client *client)
mfd_remove_devices(aat2870->dev); mfd_remove_devices(aat2870->dev);
aat2870_disable(aat2870); aat2870_disable(aat2870);
if (aat2870->en_pin >= 0)
gpio_free(aat2870->en_pin);
if (aat2870->uninit) if (aat2870->uninit)
aat2870->uninit(aat2870); aat2870->uninit(aat2870);
kfree(aat2870);
return 0; return 0;
} }
......
...@@ -248,19 +248,7 @@ static struct platform_driver ab3100_otp_driver = { ...@@ -248,19 +248,7 @@ static struct platform_driver ab3100_otp_driver = {
.remove = __exit_p(ab3100_otp_remove), .remove = __exit_p(ab3100_otp_remove),
}; };
static int __init ab3100_otp_init(void) module_platform_driver_probe(ab3100_otp_driver, ab3100_otp_probe);
{
return platform_driver_probe(&ab3100_otp_driver,
ab3100_otp_probe);
}
static void __exit ab3100_otp_exit(void)
{
platform_driver_unregister(&ab3100_otp_driver);
}
module_init(ab3100_otp_init);
module_exit(ab3100_otp_exit);
MODULE_AUTHOR("Linus Walleij <linus.walleij@stericsson.com>"); MODULE_AUTHOR("Linus Walleij <linus.walleij@stericsson.com>");
MODULE_DESCRIPTION("AB3100 OTP Readout Driver"); MODULE_DESCRIPTION("AB3100 OTP Readout Driver");
......
...@@ -458,11 +458,7 @@ static void update_latch_offset(u8 *offset, int i) ...@@ -458,11 +458,7 @@ static void update_latch_offset(u8 *offset, int i)
static int ab8500_handle_hierarchical_line(struct ab8500 *ab8500, static int ab8500_handle_hierarchical_line(struct ab8500 *ab8500,
int latch_offset, u8 latch_val) int latch_offset, u8 latch_val)
{ {
int int_bit = __ffs(latch_val); int int_bit, line, i;
int line, i;
do {
int_bit = __ffs(latch_val);
for (i = 0; i < ab8500->mask_size; i++) for (i = 0; i < ab8500->mask_size; i++)
if (ab8500->irq_reg_offset[i] == latch_offset) if (ab8500->irq_reg_offset[i] == latch_offset)
...@@ -474,6 +470,11 @@ static int ab8500_handle_hierarchical_line(struct ab8500 *ab8500, ...@@ -474,6 +470,11 @@ static int ab8500_handle_hierarchical_line(struct ab8500 *ab8500,
return -ENXIO; return -ENXIO;
} }
/* ignore masked out interrupts */
latch_val &= ~ab8500->mask[i];
while (latch_val) {
int_bit = __ffs(latch_val);
line = (i << 3) + int_bit; line = (i << 3) + int_bit;
latch_val &= ~(1 << int_bit); latch_val &= ~(1 << int_bit);
...@@ -491,7 +492,7 @@ static int ab8500_handle_hierarchical_line(struct ab8500 *ab8500, ...@@ -491,7 +492,7 @@ static int ab8500_handle_hierarchical_line(struct ab8500 *ab8500,
line += 1; line += 1;
handle_nested_irq(ab8500->irq_base + line); handle_nested_irq(ab8500->irq_base + line);
} while (latch_val); }
return 0; return 0;
} }
...@@ -1107,6 +1108,7 @@ static struct mfd_cell ab8500_devs[] = { ...@@ -1107,6 +1108,7 @@ static struct mfd_cell ab8500_devs[] = {
}, },
{ {
.name = "ab8500-usb", .name = "ab8500-usb",
.of_compatible = "stericsson,ab8500-usb",
.num_resources = ARRAY_SIZE(ab8500_usb_resources), .num_resources = ARRAY_SIZE(ab8500_usb_resources),
.resources = ab8500_usb_resources, .resources = ab8500_usb_resources,
}, },
......
...@@ -332,7 +332,7 @@ if (ad_value < 0) { ...@@ -332,7 +332,7 @@ if (ad_value < 0) {
return voltage; return voltage;
} }
EXPORT_SYMBOL(ab8500_gpadc_convert); EXPORT_SYMBOL(ab8500_gpadc_sw_hw_convert);
/** /**
* ab8500_gpadc_read_raw() - gpadc read * ab8500_gpadc_read_raw() - gpadc read
......
...@@ -242,7 +242,7 @@ static int __init ab8500_sysctrl_init(void) ...@@ -242,7 +242,7 @@ static int __init ab8500_sysctrl_init(void)
{ {
return platform_driver_register(&ab8500_sysctrl_driver); return platform_driver_register(&ab8500_sysctrl_driver);
} }
subsys_initcall(ab8500_sysctrl_init); arch_initcall(ab8500_sysctrl_init);
MODULE_AUTHOR("Mattias Nilsson <mattias.i.nilsson@stericsson.com"); MODULE_AUTHOR("Mattias Nilsson <mattias.i.nilsson@stericsson.com");
MODULE_DESCRIPTION("AB8500 system control driver"); MODULE_DESCRIPTION("AB8500 system control driver");
......
...@@ -36,6 +36,7 @@ struct adp5520_chip { ...@@ -36,6 +36,7 @@ struct adp5520_chip {
struct blocking_notifier_head notifier_list; struct blocking_notifier_head notifier_list;
int irq; int irq;
unsigned long id; unsigned long id;
uint8_t mode;
}; };
static int __adp5520_read(struct i2c_client *client, static int __adp5520_read(struct i2c_client *client,
...@@ -326,7 +327,10 @@ static int adp5520_suspend(struct device *dev) ...@@ -326,7 +327,10 @@ static int adp5520_suspend(struct device *dev)
struct i2c_client *client = to_i2c_client(dev); struct i2c_client *client = to_i2c_client(dev);
struct adp5520_chip *chip = dev_get_drvdata(&client->dev); struct adp5520_chip *chip = dev_get_drvdata(&client->dev);
adp5520_clr_bits(chip->dev, ADP5520_MODE_STATUS, ADP5520_nSTNBY); adp5520_read(chip->dev, ADP5520_MODE_STATUS, &chip->mode);
/* All other bits are W1C */
chip->mode &= ADP5520_BL_EN | ADP5520_DIM_EN | ADP5520_nSTNBY;
adp5520_write(chip->dev, ADP5520_MODE_STATUS, 0);
return 0; return 0;
} }
...@@ -335,7 +339,7 @@ static int adp5520_resume(struct device *dev) ...@@ -335,7 +339,7 @@ static int adp5520_resume(struct device *dev)
struct i2c_client *client = to_i2c_client(dev); struct i2c_client *client = to_i2c_client(dev);
struct adp5520_chip *chip = dev_get_drvdata(&client->dev); struct adp5520_chip *chip = dev_get_drvdata(&client->dev);
adp5520_set_bits(chip->dev, ADP5520_MODE_STATUS, ADP5520_nSTNBY); adp5520_write(chip->dev, ADP5520_MODE_STATUS, chip->mode);
return 0; return 0;
} }
#endif #endif
...@@ -360,17 +364,7 @@ static struct i2c_driver adp5520_driver = { ...@@ -360,17 +364,7 @@ static struct i2c_driver adp5520_driver = {
.id_table = adp5520_id, .id_table = adp5520_id,
}; };
static int __init adp5520_init(void) module_i2c_driver(adp5520_driver);
{
return i2c_add_driver(&adp5520_driver);
}
module_init(adp5520_init);
static void __exit adp5520_exit(void)
{
i2c_del_driver(&adp5520_driver);
}
module_exit(adp5520_exit);
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_DESCRIPTION("ADP5520(01) PMIC-MFD Driver"); MODULE_DESCRIPTION("ADP5520(01) PMIC-MFD Driver");
......
This diff is collapsed.
...@@ -94,6 +94,7 @@ static irqreturn_t arizona_ctrlif_err(int irq, void *data) ...@@ -94,6 +94,7 @@ static irqreturn_t arizona_ctrlif_err(int irq, void *data)
static irqreturn_t arizona_irq_thread(int irq, void *data) static irqreturn_t arizona_irq_thread(int irq, void *data)
{ {
struct arizona *arizona = data; struct arizona *arizona = data;
bool poll;
unsigned int val; unsigned int val;
int ret; int ret;
...@@ -103,6 +104,9 @@ static irqreturn_t arizona_irq_thread(int irq, void *data) ...@@ -103,6 +104,9 @@ static irqreturn_t arizona_irq_thread(int irq, void *data)
return IRQ_NONE; return IRQ_NONE;
} }
do {
poll = false;
/* Always handle the AoD domain */ /* Always handle the AoD domain */
handle_nested_irq(irq_find_mapping(arizona->virq, 0)); handle_nested_irq(irq_find_mapping(arizona->virq, 0));
...@@ -110,13 +114,29 @@ static irqreturn_t arizona_irq_thread(int irq, void *data) ...@@ -110,13 +114,29 @@ static irqreturn_t arizona_irq_thread(int irq, void *data)
* Check if one of the main interrupts is asserted and only * Check if one of the main interrupts is asserted and only
* check that domain if it is. * check that domain if it is.
*/ */
ret = regmap_read(arizona->regmap, ARIZONA_IRQ_PIN_STATUS, &val); ret = regmap_read(arizona->regmap, ARIZONA_IRQ_PIN_STATUS,
&val);
if (ret == 0 && val & ARIZONA_IRQ1_STS) { if (ret == 0 && val & ARIZONA_IRQ1_STS) {
handle_nested_irq(irq_find_mapping(arizona->virq, 1)); handle_nested_irq(irq_find_mapping(arizona->virq, 1));
} else if (ret != 0) { } else if (ret != 0) {
dev_err(arizona->dev, "Failed to read main IRQ status: %d\n", dev_err(arizona->dev,
ret); "Failed to read main IRQ status: %d\n", ret);
}
/*
* Poll the IRQ pin status to see if we're really done
* if the interrupt controller can't do it for us.
*/
if (!arizona->pdata.irq_gpio) {
break;
} else if (arizona->pdata.irq_flags & IRQF_TRIGGER_RISING &&
gpio_get_value_cansleep(arizona->pdata.irq_gpio)) {
poll = true;
} else if (arizona->pdata.irq_flags & IRQF_TRIGGER_FALLING &&
!gpio_get_value_cansleep(arizona->pdata.irq_gpio)) {
poll = true;
} }
} while (poll);
pm_runtime_mark_last_busy(arizona->dev); pm_runtime_mark_last_busy(arizona->dev);
pm_runtime_put_autosuspend(arizona->dev); pm_runtime_put_autosuspend(arizona->dev);
...@@ -169,6 +189,7 @@ int arizona_irq_init(struct arizona *arizona) ...@@ -169,6 +189,7 @@ int arizona_irq_init(struct arizona *arizona)
int ret, i; int ret, i;
const struct regmap_irq_chip *aod, *irq; const struct regmap_irq_chip *aod, *irq;
bool ctrlif_error = true; bool ctrlif_error = true;
struct irq_data *irq_data;
switch (arizona->type) { switch (arizona->type) {
#ifdef CONFIG_MFD_WM5102 #ifdef CONFIG_MFD_WM5102
...@@ -192,7 +213,36 @@ int arizona_irq_init(struct arizona *arizona) ...@@ -192,7 +213,36 @@ int arizona_irq_init(struct arizona *arizona)
return -EINVAL; return -EINVAL;
} }
if (arizona->pdata.irq_active_high) { /* Disable all wake sources by default */
regmap_write(arizona->regmap, ARIZONA_WAKE_CONTROL, 0);
/* Read the flags from the interrupt controller if not specified */
if (!arizona->pdata.irq_flags) {
irq_data = irq_get_irq_data(arizona->irq);
if (!irq_data) {
dev_err(arizona->dev, "Invalid IRQ: %d\n",
arizona->irq);
return -EINVAL;
}
arizona->pdata.irq_flags = irqd_get_trigger_type(irq_data);
switch (arizona->pdata.irq_flags) {
case IRQF_TRIGGER_LOW:
case IRQF_TRIGGER_HIGH:
case IRQF_TRIGGER_RISING:
case IRQF_TRIGGER_FALLING:
break;
case IRQ_TYPE_NONE:
default:
/* Device default */
arizona->pdata.irq_flags = IRQF_TRIGGER_LOW;
break;
}
}
if (arizona->pdata.irq_flags & (IRQF_TRIGGER_HIGH |
IRQF_TRIGGER_RISING)) {
ret = regmap_update_bits(arizona->regmap, ARIZONA_IRQ_CTRL_1, ret = regmap_update_bits(arizona->regmap, ARIZONA_IRQ_CTRL_1,
ARIZONA_IRQ_POL, 0); ARIZONA_IRQ_POL, 0);
if (ret != 0) { if (ret != 0) {
...@@ -200,12 +250,10 @@ int arizona_irq_init(struct arizona *arizona) ...@@ -200,12 +250,10 @@ int arizona_irq_init(struct arizona *arizona)
ret); ret);
goto err; goto err;
} }
flags |= IRQF_TRIGGER_HIGH;
} else {
flags |= IRQF_TRIGGER_LOW;
} }
flags |= arizona->pdata.irq_flags;
/* Allocate a virtual IRQ domain to distribute to the regmap domains */ /* Allocate a virtual IRQ domain to distribute to the regmap domains */
arizona->virq = irq_domain_add_linear(NULL, 2, &arizona_domain_ops, arizona->virq = irq_domain_add_linear(NULL, 2, &arizona_domain_ops,
arizona); arizona);
...@@ -257,11 +305,31 @@ int arizona_irq_init(struct arizona *arizona) ...@@ -257,11 +305,31 @@ int arizona_irq_init(struct arizona *arizona)
} }
} }
/* Used to emulate edge trigger and to work around broken pinmux */
if (arizona->pdata.irq_gpio) {
if (gpio_to_irq(arizona->pdata.irq_gpio) != arizona->irq) {
dev_warn(arizona->dev, "IRQ %d is not GPIO %d (%d)\n",
arizona->irq, arizona->pdata.irq_gpio,
gpio_to_irq(arizona->pdata.irq_gpio));
arizona->irq = gpio_to_irq(arizona->pdata.irq_gpio);
}
ret = devm_gpio_request_one(arizona->dev,
arizona->pdata.irq_gpio,
GPIOF_IN, "arizona IRQ");
if (ret != 0) {
dev_err(arizona->dev,
"Failed to request IRQ GPIO %d:: %d\n",
arizona->pdata.irq_gpio, ret);
arizona->pdata.irq_gpio = 0;
}
}
ret = request_threaded_irq(arizona->irq, NULL, arizona_irq_thread, ret = request_threaded_irq(arizona->irq, NULL, arizona_irq_thread,
flags, "arizona", arizona); flags, "arizona", arizona);
if (ret != 0) { if (ret != 0) {
dev_err(arizona->dev, "Failed to request IRQ %d: %d\n", dev_err(arizona->dev, "Failed to request primary IRQ %d: %d\n",
arizona->irq, ret); arizona->irq, ret);
goto err_main_irq; goto err_main_irq;
} }
......
...@@ -67,7 +67,7 @@ static int arizona_spi_probe(struct spi_device *spi) ...@@ -67,7 +67,7 @@ static int arizona_spi_probe(struct spi_device *spi)
static int arizona_spi_remove(struct spi_device *spi) static int arizona_spi_remove(struct spi_device *spi)
{ {
struct arizona *arizona = dev_get_drvdata(&spi->dev); struct arizona *arizona = spi_get_drvdata(spi);
arizona_dev_exit(arizona); arizona_dev_exit(arizona);
return 0; return 0;
} }
......
...@@ -112,16 +112,34 @@ static const struct regmap_config as3711_regmap_config = { ...@@ -112,16 +112,34 @@ static const struct regmap_config as3711_regmap_config = {
.cache_type = REGCACHE_RBTREE, .cache_type = REGCACHE_RBTREE,
}; };
#ifdef CONFIG_OF
static struct of_device_id as3711_of_match[] = {
{.compatible = "ams,as3711",},
{}
};
MODULE_DEVICE_TABLE(of, as3711_of_match);
#endif
static int as3711_i2c_probe(struct i2c_client *client, static int as3711_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id) const struct i2c_device_id *id)
{ {
struct as3711 *as3711; struct as3711 *as3711;
struct as3711_platform_data *pdata = client->dev.platform_data; struct as3711_platform_data *pdata;
unsigned int id1, id2; unsigned int id1, id2;
int ret; int ret;
if (!client->dev.of_node) {
pdata = client->dev.platform_data;
if (!pdata) if (!pdata)
dev_dbg(&client->dev, "Platform data not found\n"); dev_dbg(&client->dev, "Platform data not found\n");
} else {
pdata = devm_kzalloc(&client->dev,
sizeof(*pdata), GFP_KERNEL);
if (!pdata) {
dev_err(&client->dev, "Failed to allocate pdata\n");
return -ENOMEM;
}
}
as3711 = devm_kzalloc(&client->dev, sizeof(struct as3711), GFP_KERNEL); as3711 = devm_kzalloc(&client->dev, sizeof(struct as3711), GFP_KERNEL);
if (!as3711) { if (!as3711) {
...@@ -193,6 +211,7 @@ static struct i2c_driver as3711_i2c_driver = { ...@@ -193,6 +211,7 @@ static struct i2c_driver as3711_i2c_driver = {
.driver = { .driver = {
.name = "as3711", .name = "as3711",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.of_match_table = of_match_ptr(as3711_of_match),
}, },
.probe = as3711_i2c_probe, .probe = as3711_i2c_probe,
.remove = as3711_i2c_remove, .remove = as3711_i2c_remove,
......
/*
* ChromeOS EC multi-function device
*
* Copyright (C) 2012 Google, Inc
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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.
*
* The ChromeOS EC multi function device is used to mux all the requests
* to the EC device for its multiple features: keyboard controller,
* battery charging and regulator control, firmware update.
*/
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/mfd/core.h>
#include <linux/mfd/cros_ec.h>
#include <linux/mfd/cros_ec_commands.h>
int cros_ec_prepare_tx(struct cros_ec_device *ec_dev,
struct cros_ec_msg *msg)
{
uint8_t *out;
int csum, i;
BUG_ON(msg->out_len > EC_HOST_PARAM_SIZE);
out = ec_dev->dout;
out[0] = EC_CMD_VERSION0 + msg->version;
out[1] = msg->cmd;
out[2] = msg->out_len;
csum = out[0] + out[1] + out[2];
for (i = 0; i < msg->out_len; i++)
csum += out[EC_MSG_TX_HEADER_BYTES + i] = msg->out_buf[i];
out[EC_MSG_TX_HEADER_BYTES + msg->out_len] = (uint8_t)(csum & 0xff);
return EC_MSG_TX_PROTO_BYTES + msg->out_len;
}
EXPORT_SYMBOL(cros_ec_prepare_tx);
static int cros_ec_command_sendrecv(struct cros_ec_device *ec_dev,
uint16_t cmd, void *out_buf, int out_len,
void *in_buf, int in_len)
{
struct cros_ec_msg msg;
msg.version = cmd >> 8;
msg.cmd = cmd & 0xff;
msg.out_buf = out_buf;
msg.out_len = out_len;
msg.in_buf = in_buf;
msg.in_len = in_len;
return ec_dev->command_xfer(ec_dev, &msg);
}
static int cros_ec_command_recv(struct cros_ec_device *ec_dev,
uint16_t cmd, void *buf, int buf_len)
{
return cros_ec_command_sendrecv(ec_dev, cmd, NULL, 0, buf, buf_len);
}
static int cros_ec_command_send(struct cros_ec_device *ec_dev,
uint16_t cmd, void *buf, int buf_len)
{
return cros_ec_command_sendrecv(ec_dev, cmd, buf, buf_len, NULL, 0);
}
static irqreturn_t ec_irq_thread(int irq, void *data)
{
struct cros_ec_device *ec_dev = data;
if (device_may_wakeup(ec_dev->dev))
pm_wakeup_event(ec_dev->dev, 0);
blocking_notifier_call_chain(&ec_dev->event_notifier, 1, ec_dev);
return IRQ_HANDLED;
}
static struct mfd_cell cros_devs[] = {
{
.name = "cros-ec-keyb",
.id = 1,
.of_compatible = "google,cros-ec-keyb",
},
};
int cros_ec_register(struct cros_ec_device *ec_dev)
{
struct device *dev = ec_dev->dev;
int err = 0;
BLOCKING_INIT_NOTIFIER_HEAD(&ec_dev->event_notifier);
ec_dev->command_send = cros_ec_command_send;
ec_dev->command_recv = cros_ec_command_recv;
ec_dev->command_sendrecv = cros_ec_command_sendrecv;
if (ec_dev->din_size) {
ec_dev->din = kmalloc(ec_dev->din_size, GFP_KERNEL);
if (!ec_dev->din) {
err = -ENOMEM;
goto fail_din;
}
}
if (ec_dev->dout_size) {
ec_dev->dout = kmalloc(ec_dev->dout_size, GFP_KERNEL);
if (!ec_dev->dout) {
err = -ENOMEM;
goto fail_dout;
}
}
if (!ec_dev->irq) {
dev_dbg(dev, "no valid IRQ: %d\n", ec_dev->irq);
goto fail_irq;
}
err = request_threaded_irq(ec_dev->irq, NULL, ec_irq_thread,
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
"chromeos-ec", ec_dev);
if (err) {
dev_err(dev, "request irq %d: error %d\n", ec_dev->irq, err);
goto fail_irq;
}
err = mfd_add_devices(dev, 0, cros_devs,
ARRAY_SIZE(cros_devs),
NULL, ec_dev->irq, NULL);
if (err) {
dev_err(dev, "failed to add mfd devices\n");
goto fail_mfd;
}
dev_info(dev, "Chrome EC (%s)\n", ec_dev->name);
return 0;
fail_mfd:
free_irq(ec_dev->irq, ec_dev);
fail_irq:
kfree(ec_dev->dout);
fail_dout:
kfree(ec_dev->din);
fail_din:
return err;
}
EXPORT_SYMBOL(cros_ec_register);
int cros_ec_remove(struct cros_ec_device *ec_dev)
{
mfd_remove_devices(ec_dev->dev);
free_irq(ec_dev->irq, ec_dev);
kfree(ec_dev->dout);
kfree(ec_dev->din);
return 0;
}
EXPORT_SYMBOL(cros_ec_remove);
#ifdef CONFIG_PM_SLEEP
int cros_ec_suspend(struct cros_ec_device *ec_dev)
{
struct device *dev = ec_dev->dev;
if (device_may_wakeup(dev))
ec_dev->wake_enabled = !enable_irq_wake(ec_dev->irq);
disable_irq(ec_dev->irq);
ec_dev->was_wake_device = ec_dev->wake_enabled;
return 0;
}
EXPORT_SYMBOL(cros_ec_suspend);
int cros_ec_resume(struct cros_ec_device *ec_dev)
{
enable_irq(ec_dev->irq);
if (ec_dev->wake_enabled) {
disable_irq_wake(ec_dev->irq);
ec_dev->wake_enabled = 0;
}
return 0;
}
EXPORT_SYMBOL(cros_ec_resume);
#endif
/*
* ChromeOS EC multi-function device (I2C)
*
* Copyright (C) 2012 Google, Inc
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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/kernel.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/mfd/cros_ec.h>
#include <linux/mfd/cros_ec_commands.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
static inline struct cros_ec_device *to_ec_dev(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
return i2c_get_clientdata(client);
}
static int cros_ec_command_xfer(struct cros_ec_device *ec_dev,
struct cros_ec_msg *msg)
{
struct i2c_client *client = ec_dev->priv;
int ret = -ENOMEM;
int i;
int packet_len;
u8 *out_buf = NULL;
u8 *in_buf = NULL;
u8 sum;
struct i2c_msg i2c_msg[2];
i2c_msg[0].addr = client->addr;
i2c_msg[0].flags = 0;
i2c_msg[1].addr = client->addr;
i2c_msg[1].flags = I2C_M_RD;
/*
* allocate larger packet (one byte for checksum, one byte for
* length, and one for result code)
*/
packet_len = msg->in_len + 3;
in_buf = kzalloc(packet_len, GFP_KERNEL);
if (!in_buf)
goto done;
i2c_msg[1].len = packet_len;
i2c_msg[1].buf = (char *)in_buf;
/*
* allocate larger packet (one byte for checksum, one for
* command code, one for length, and one for command version)
*/
packet_len = msg->out_len + 4;
out_buf = kzalloc(packet_len, GFP_KERNEL);
if (!out_buf)
goto done;
i2c_msg[0].len = packet_len;
i2c_msg[0].buf = (char *)out_buf;
out_buf[0] = EC_CMD_VERSION0 + msg->version;
out_buf[1] = msg->cmd;
out_buf[2] = msg->out_len;
/* copy message payload and compute checksum */
sum = out_buf[0] + out_buf[1] + out_buf[2];
for (i = 0; i < msg->out_len; i++) {
out_buf[3 + i] = msg->out_buf[i];
sum += out_buf[3 + i];
}
out_buf[3 + msg->out_len] = sum;
/* send command to EC and read answer */
ret = i2c_transfer(client->adapter, i2c_msg, 2);
if (ret < 0) {
dev_err(ec_dev->dev, "i2c transfer failed: %d\n", ret);
goto done;
} else if (ret != 2) {
dev_err(ec_dev->dev, "failed to get response: %d\n", ret);
ret = -EIO;
goto done;
}
/* check response error code */
if (i2c_msg[1].buf[0]) {
dev_warn(ec_dev->dev, "command 0x%02x returned an error %d\n",
msg->cmd, i2c_msg[1].buf[0]);
ret = -EINVAL;
goto done;
}
/* copy response packet payload and compute checksum */
sum = in_buf[0] + in_buf[1];
for (i = 0; i < msg->in_len; i++) {
msg->in_buf[i] = in_buf[2 + i];
sum += in_buf[2 + i];
}
dev_dbg(ec_dev->dev, "packet: %*ph, sum = %02x\n",
i2c_msg[1].len, in_buf, sum);
if (sum != in_buf[2 + msg->in_len]) {
dev_err(ec_dev->dev, "bad packet checksum\n");
ret = -EBADMSG;
goto done;
}
ret = 0;
done:
kfree(in_buf);
kfree(out_buf);
return ret;
}
static int cros_ec_probe_i2c(struct i2c_client *client,
const struct i2c_device_id *dev_id)
{
struct device *dev = &client->dev;
struct cros_ec_device *ec_dev = NULL;
int err;
ec_dev = devm_kzalloc(dev, sizeof(*ec_dev), GFP_KERNEL);
if (!ec_dev)
return -ENOMEM;
i2c_set_clientdata(client, ec_dev);
ec_dev->name = "I2C";
ec_dev->dev = dev;
ec_dev->priv = client;
ec_dev->irq = client->irq;
ec_dev->command_xfer = cros_ec_command_xfer;
ec_dev->ec_name = client->name;
ec_dev->phys_name = client->adapter->name;
ec_dev->parent = &client->dev;
err = cros_ec_register(ec_dev);
if (err) {
dev_err(dev, "cannot register EC\n");
return err;
}
return 0;
}
static int cros_ec_remove_i2c(struct i2c_client *client)
{
struct cros_ec_device *ec_dev = i2c_get_clientdata(client);
cros_ec_remove(ec_dev);
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int cros_ec_i2c_suspend(struct device *dev)
{
struct cros_ec_device *ec_dev = to_ec_dev(dev);
return cros_ec_suspend(ec_dev);
}
static int cros_ec_i2c_resume(struct device *dev)
{
struct cros_ec_device *ec_dev = to_ec_dev(dev);
return cros_ec_resume(ec_dev);
}
#endif
static SIMPLE_DEV_PM_OPS(cros_ec_i2c_pm_ops, cros_ec_i2c_suspend,
cros_ec_i2c_resume);
static const struct i2c_device_id cros_ec_i2c_id[] = {
{ "cros-ec-i2c", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, cros_ec_i2c_id);
static struct i2c_driver cros_ec_driver = {
.driver = {
.name = "cros-ec-i2c",
.owner = THIS_MODULE,
.pm = &cros_ec_i2c_pm_ops,
},
.probe = cros_ec_probe_i2c,
.remove = cros_ec_remove_i2c,
.id_table = cros_ec_i2c_id,
};
module_i2c_driver(cros_ec_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("ChromeOS EC multi function device");
/*
* ChromeOS EC multi-function device (SPI)
*
* Copyright (C) 2012 Google, Inc
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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/delay.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mfd/cros_ec.h>
#include <linux/mfd/cros_ec_commands.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/spi/spi.h>
/* The header byte, which follows the preamble */
#define EC_MSG_HEADER 0xec
/*
* Number of EC preamble bytes we read at a time. Since it takes
* about 400-500us for the EC to respond there is not a lot of
* point in tuning this. If the EC could respond faster then
* we could increase this so that might expect the preamble and
* message to occur in a single transaction. However, the maximum
* SPI transfer size is 256 bytes, so at 5MHz we need a response
* time of perhaps <320us (200 bytes / 1600 bits).
*/
#define EC_MSG_PREAMBLE_COUNT 32
/*
* We must get a response from the EC in 5ms. This is a very long
* time, but the flash write command can take 2-3ms. The EC command
* processing is currently not very fast (about 500us). We could
* look at speeding this up and making the flash write command a
* 'slow' command, requiring a GET_STATUS wait loop, like flash
* erase.
*/
#define EC_MSG_DEADLINE_MS 5
/*
* Time between raising the SPI chip select (for the end of a
* transaction) and dropping it again (for the next transaction).
* If we go too fast, the EC will miss the transaction. It seems
* that 50us is enough with the 16MHz STM32 EC.
*/
#define EC_SPI_RECOVERY_TIME_NS (50 * 1000)
/**
* struct cros_ec_spi - information about a SPI-connected EC
*
* @spi: SPI device we are connected to
* @last_transfer_ns: time that we last finished a transfer, or 0 if there
* if no record
*/
struct cros_ec_spi {
struct spi_device *spi;
s64 last_transfer_ns;
};
static void debug_packet(struct device *dev, const char *name, u8 *ptr,
int len)
{
#ifdef DEBUG
int i;
dev_dbg(dev, "%s: ", name);
for (i = 0; i < len; i++)
dev_cont(dev, " %02x", ptr[i]);
#endif
}
/**
* cros_ec_spi_receive_response - Receive a response from the EC.
*
* This function has two phases: reading the preamble bytes (since if we read
* data from the EC before it is ready to send, we just get preamble) and
* reading the actual message.
*
* The received data is placed into ec_dev->din.
*
* @ec_dev: ChromeOS EC device
* @need_len: Number of message bytes we need to read
*/
static int cros_ec_spi_receive_response(struct cros_ec_device *ec_dev,
int need_len)
{
struct cros_ec_spi *ec_spi = ec_dev->priv;
struct spi_transfer trans;
struct spi_message msg;
u8 *ptr, *end;
int ret;
unsigned long deadline;
int todo;
/* Receive data until we see the header byte */
deadline = jiffies + msecs_to_jiffies(EC_MSG_DEADLINE_MS);
do {
memset(&trans, '\0', sizeof(trans));
trans.cs_change = 1;
trans.rx_buf = ptr = ec_dev->din;
trans.len = EC_MSG_PREAMBLE_COUNT;
spi_message_init(&msg);
spi_message_add_tail(&trans, &msg);
ret = spi_sync(ec_spi->spi, &msg);
if (ret < 0) {
dev_err(ec_dev->dev, "spi transfer failed: %d\n", ret);
return ret;
}
for (end = ptr + EC_MSG_PREAMBLE_COUNT; ptr != end; ptr++) {
if (*ptr == EC_MSG_HEADER) {
dev_dbg(ec_dev->dev, "msg found at %ld\n",
ptr - ec_dev->din);
break;
}
}
if (time_after(jiffies, deadline)) {
dev_warn(ec_dev->dev, "EC failed to respond in time\n");
return -ETIMEDOUT;
}
} while (ptr == end);
/*
* ptr now points to the header byte. Copy any valid data to the
* start of our buffer
*/
todo = end - ++ptr;
BUG_ON(todo < 0 || todo > ec_dev->din_size);
todo = min(todo, need_len);
memmove(ec_dev->din, ptr, todo);
ptr = ec_dev->din + todo;
dev_dbg(ec_dev->dev, "need %d, got %d bytes from preamble\n",
need_len, todo);
need_len -= todo;
/* Receive data until we have it all */
while (need_len > 0) {
/*
* We can't support transfers larger than the SPI FIFO size
* unless we have DMA. We don't have DMA on the ISP SPI ports
* for Exynos. We need a way of asking SPI driver for
* maximum-supported transfer size.
*/
todo = min(need_len, 256);
dev_dbg(ec_dev->dev, "loop, todo=%d, need_len=%d, ptr=%ld\n",
todo, need_len, ptr - ec_dev->din);
memset(&trans, '\0', sizeof(trans));
trans.cs_change = 1;
trans.rx_buf = ptr;
trans.len = todo;
spi_message_init(&msg);
spi_message_add_tail(&trans, &msg);
/* send command to EC and read answer */
BUG_ON((u8 *)trans.rx_buf - ec_dev->din + todo >
ec_dev->din_size);
ret = spi_sync(ec_spi->spi, &msg);
if (ret < 0) {
dev_err(ec_dev->dev, "spi transfer failed: %d\n", ret);
return ret;
}
debug_packet(ec_dev->dev, "interim", ptr, todo);
ptr += todo;
need_len -= todo;
}
dev_dbg(ec_dev->dev, "loop done, ptr=%ld\n", ptr - ec_dev->din);
return 0;
}
/**
* cros_ec_command_spi_xfer - Transfer a message over SPI and receive the reply
*
* @ec_dev: ChromeOS EC device
* @ec_msg: Message to transfer
*/
static int cros_ec_command_spi_xfer(struct cros_ec_device *ec_dev,
struct cros_ec_msg *ec_msg)
{
struct cros_ec_spi *ec_spi = ec_dev->priv;
struct spi_transfer trans;
struct spi_message msg;
int i, len;
u8 *ptr;
int sum;
int ret = 0, final_ret;
struct timespec ts;
len = cros_ec_prepare_tx(ec_dev, ec_msg);
dev_dbg(ec_dev->dev, "prepared, len=%d\n", len);
/* If it's too soon to do another transaction, wait */
if (ec_spi->last_transfer_ns) {
struct timespec ts;
unsigned long delay; /* The delay completed so far */
ktime_get_ts(&ts);
delay = timespec_to_ns(&ts) - ec_spi->last_transfer_ns;
if (delay < EC_SPI_RECOVERY_TIME_NS)
ndelay(delay);
}
/* Transmit phase - send our message */
debug_packet(ec_dev->dev, "out", ec_dev->dout, len);
memset(&trans, '\0', sizeof(trans));
trans.tx_buf = ec_dev->dout;
trans.len = len;
trans.cs_change = 1;
spi_message_init(&msg);
spi_message_add_tail(&trans, &msg);
ret = spi_sync(ec_spi->spi, &msg);
/* Get the response */
if (!ret) {
ret = cros_ec_spi_receive_response(ec_dev,
ec_msg->in_len + EC_MSG_TX_PROTO_BYTES);
} else {
dev_err(ec_dev->dev, "spi transfer failed: %d\n", ret);
}
/* turn off CS */
spi_message_init(&msg);
final_ret = spi_sync(ec_spi->spi, &msg);
ktime_get_ts(&ts);
ec_spi->last_transfer_ns = timespec_to_ns(&ts);
if (!ret)
ret = final_ret;
if (ret < 0) {
dev_err(ec_dev->dev, "spi transfer failed: %d\n", ret);
return ret;
}
/* check response error code */
ptr = ec_dev->din;
if (ptr[0]) {
dev_warn(ec_dev->dev, "command 0x%02x returned an error %d\n",
ec_msg->cmd, ptr[0]);
debug_packet(ec_dev->dev, "in_err", ptr, len);
return -EINVAL;
}
len = ptr[1];
sum = ptr[0] + ptr[1];
if (len > ec_msg->in_len) {
dev_err(ec_dev->dev, "packet too long (%d bytes, expected %d)",
len, ec_msg->in_len);
return -ENOSPC;
}
/* copy response packet payload and compute checksum */
for (i = 0; i < len; i++) {
sum += ptr[i + 2];
if (ec_msg->in_len)
ec_msg->in_buf[i] = ptr[i + 2];
}
sum &= 0xff;
debug_packet(ec_dev->dev, "in", ptr, len + 3);
if (sum != ptr[len + 2]) {
dev_err(ec_dev->dev,
"bad packet checksum, expected %02x, got %02x\n",
sum, ptr[len + 2]);
return -EBADMSG;
}
return 0;
}
static int cros_ec_probe_spi(struct spi_device *spi)
{
struct device *dev = &spi->dev;
struct cros_ec_device *ec_dev;
struct cros_ec_spi *ec_spi;
int err;
spi->bits_per_word = 8;
spi->mode = SPI_MODE_0;
err = spi_setup(spi);
if (err < 0)
return err;
ec_spi = devm_kzalloc(dev, sizeof(*ec_spi), GFP_KERNEL);
if (ec_spi == NULL)
return -ENOMEM;
ec_spi->spi = spi;
ec_dev = devm_kzalloc(dev, sizeof(*ec_dev), GFP_KERNEL);
if (!ec_dev)
return -ENOMEM;
spi_set_drvdata(spi, ec_dev);
ec_dev->name = "SPI";
ec_dev->dev = dev;
ec_dev->priv = ec_spi;
ec_dev->irq = spi->irq;
ec_dev->command_xfer = cros_ec_command_spi_xfer;
ec_dev->ec_name = ec_spi->spi->modalias;
ec_dev->phys_name = dev_name(&ec_spi->spi->dev);
ec_dev->parent = &ec_spi->spi->dev;
ec_dev->din_size = EC_MSG_BYTES + EC_MSG_PREAMBLE_COUNT;
ec_dev->dout_size = EC_MSG_BYTES;
err = cros_ec_register(ec_dev);
if (err) {
dev_err(dev, "cannot register EC\n");
return err;
}
return 0;
}
static int cros_ec_remove_spi(struct spi_device *spi)
{
struct cros_ec_device *ec_dev;
ec_dev = spi_get_drvdata(spi);
cros_ec_remove(ec_dev);
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int cros_ec_spi_suspend(struct device *dev)
{
struct cros_ec_device *ec_dev = dev_get_drvdata(dev);
return cros_ec_suspend(ec_dev);
}
static int cros_ec_spi_resume(struct device *dev)
{
struct cros_ec_device *ec_dev = dev_get_drvdata(dev);
return cros_ec_resume(ec_dev);
}
#endif
static SIMPLE_DEV_PM_OPS(cros_ec_spi_pm_ops, cros_ec_spi_suspend,
cros_ec_spi_resume);
static const struct spi_device_id cros_ec_spi_id[] = {
{ "cros-ec-spi", 0 },
{ }
};
MODULE_DEVICE_TABLE(spi, cros_ec_spi_id);
static struct spi_driver cros_ec_driver_spi = {
.driver = {
.name = "cros-ec-spi",
.owner = THIS_MODULE,
.pm = &cros_ec_spi_pm_ops,
},
.probe = cros_ec_probe_spi,
.remove = cros_ec_remove_spi,
.id_table = cros_ec_spi_id,
};
module_spi_driver(cros_ec_driver_spi);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("ChromeOS EC multi function device (SPI)");
...@@ -499,7 +499,8 @@ static int da903x_probe(struct i2c_client *client, ...@@ -499,7 +499,8 @@ static int da903x_probe(struct i2c_client *client,
unsigned int tmp; unsigned int tmp;
int ret; int ret;
chip = kzalloc(sizeof(struct da903x_chip), GFP_KERNEL); chip = devm_kzalloc(&client->dev, sizeof(struct da903x_chip),
GFP_KERNEL);
if (chip == NULL) if (chip == NULL)
return -ENOMEM; return -ENOMEM;
...@@ -515,33 +516,27 @@ static int da903x_probe(struct i2c_client *client, ...@@ -515,33 +516,27 @@ static int da903x_probe(struct i2c_client *client,
ret = chip->ops->init_chip(chip); ret = chip->ops->init_chip(chip);
if (ret) if (ret)
goto out_free_chip; return ret;
/* mask and clear all IRQs */ /* mask and clear all IRQs */
chip->events_mask = 0xffffffff; chip->events_mask = 0xffffffff;
chip->ops->mask_events(chip, chip->events_mask); chip->ops->mask_events(chip, chip->events_mask);
chip->ops->read_events(chip, &tmp); chip->ops->read_events(chip, &tmp);
ret = request_irq(client->irq, da903x_irq_handler, ret = devm_request_irq(&client->dev, client->irq, da903x_irq_handler,
IRQF_TRIGGER_FALLING, IRQF_TRIGGER_FALLING,
"da903x", chip); "da903x", chip);
if (ret) { if (ret) {
dev_err(&client->dev, "failed to request irq %d\n", dev_err(&client->dev, "failed to request irq %d\n",
client->irq); client->irq);
goto out_free_chip; return ret;
} }
ret = da903x_add_subdevs(chip, pdata); ret = da903x_add_subdevs(chip, pdata);
if (ret) if (ret)
goto out_free_irq; return ret;
return 0; return 0;
out_free_irq:
free_irq(client->irq, chip);
out_free_chip:
kfree(chip);
return ret;
} }
static int da903x_remove(struct i2c_client *client) static int da903x_remove(struct i2c_client *client)
...@@ -549,8 +544,6 @@ static int da903x_remove(struct i2c_client *client) ...@@ -549,8 +544,6 @@ static int da903x_remove(struct i2c_client *client)
struct da903x_chip *chip = i2c_get_clientdata(client); struct da903x_chip *chip = i2c_get_clientdata(client);
da903x_remove_subdevs(chip); da903x_remove_subdevs(chip);
free_irq(client->irq, chip);
kfree(chip);
return 0; return 0;
} }
......
...@@ -38,7 +38,7 @@ static int da9052_spi_probe(struct spi_device *spi) ...@@ -38,7 +38,7 @@ static int da9052_spi_probe(struct spi_device *spi)
da9052->dev = &spi->dev; da9052->dev = &spi->dev;
da9052->chip_irq = spi->irq; da9052->chip_irq = spi->irq;
dev_set_drvdata(&spi->dev, da9052); spi_set_drvdata(spi, da9052);
da9052_regmap_config.read_flag_mask = 1; da9052_regmap_config.read_flag_mask = 1;
da9052_regmap_config.write_flag_mask = 0; da9052_regmap_config.write_flag_mask = 0;
...@@ -60,7 +60,7 @@ static int da9052_spi_probe(struct spi_device *spi) ...@@ -60,7 +60,7 @@ static int da9052_spi_probe(struct spi_device *spi)
static int da9052_spi_remove(struct spi_device *spi) static int da9052_spi_remove(struct spi_device *spi)
{ {
struct da9052 *da9052 = dev_get_drvdata(&spi->dev); struct da9052 *da9052 = spi_get_drvdata(spi);
da9052_device_exit(da9052); da9052_device_exit(da9052);
return 0; return 0;
......
...@@ -391,7 +391,7 @@ int da9055_device_init(struct da9055 *da9055) ...@@ -391,7 +391,7 @@ int da9055_device_init(struct da9055 *da9055)
da9055->irq_base = pdata->irq_base; da9055->irq_base = pdata->irq_base;
ret = regmap_add_irq_chip(da9055->regmap, da9055->chip_irq, ret = regmap_add_irq_chip(da9055->regmap, da9055->chip_irq,
IRQF_TRIGGER_HIGH | IRQF_ONESHOT, IRQF_TRIGGER_LOW | IRQF_ONESHOT,
da9055->irq_base, &da9055_regmap_irq_chip, da9055->irq_base, &da9055_regmap_irq_chip,
&da9055->irq_data); &da9055->irq_data);
if (ret < 0) if (ret < 0)
......
...@@ -177,17 +177,7 @@ static struct platform_driver davinci_vc_driver = { ...@@ -177,17 +177,7 @@ static struct platform_driver davinci_vc_driver = {
.remove = davinci_vc_remove, .remove = davinci_vc_remove,
}; };
static int __init davinci_vc_init(void) module_platform_driver_probe(davinci_vc_driver, davinci_vc_probe);
{
return platform_driver_probe(&davinci_vc_driver, davinci_vc_probe);
}
module_init(davinci_vc_init);
static void __exit davinci_vc_exit(void)
{
platform_driver_unregister(&davinci_vc_driver);
}
module_exit(davinci_vc_exit);
MODULE_AUTHOR("Miguel Aguilar"); MODULE_AUTHOR("Miguel Aguilar");
MODULE_DESCRIPTION("Texas Instruments DaVinci Voice Codec Core Interface"); MODULE_DESCRIPTION("Texas Instruments DaVinci Voice Codec Core Interface");
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/of.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/mfd/core.h> #include <linux/mfd/core.h>
...@@ -2704,6 +2705,7 @@ static void dbx500_fw_version_init(struct platform_device *pdev, ...@@ -2704,6 +2705,7 @@ static void dbx500_fw_version_init(struct platform_device *pdev,
{ {
struct resource *res; struct resource *res;
void __iomem *tcpm_base; void __iomem *tcpm_base;
u32 version;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"prcmu-tcpm"); "prcmu-tcpm");
...@@ -2713,8 +2715,10 @@ static void dbx500_fw_version_init(struct platform_device *pdev, ...@@ -2713,8 +2715,10 @@ static void dbx500_fw_version_init(struct platform_device *pdev,
return; return;
} }
tcpm_base = ioremap(res->start, resource_size(res)); tcpm_base = ioremap(res->start, resource_size(res));
if (tcpm_base != NULL) { if (!tcpm_base) {
u32 version; dev_err(&pdev->dev, "no prcmu tcpm mem region provided\n");
return;
}
version = readl(tcpm_base + version_offset); version = readl(tcpm_base + version_offset);
fw_info.version.project = (version & 0xFF); fw_info.version.project = (version & 0xFF);
...@@ -2732,7 +2736,6 @@ static void dbx500_fw_version_init(struct platform_device *pdev, ...@@ -2732,7 +2736,6 @@ static void dbx500_fw_version_init(struct platform_device *pdev,
fw_info.version.func_version, fw_info.version.func_version,
fw_info.version.errata); fw_info.version.errata);
iounmap(tcpm_base); iounmap(tcpm_base);
}
} }
void __init db8500_prcmu_early_init(u32 phy_base, u32 size) void __init db8500_prcmu_early_init(u32 phy_base, u32 size)
...@@ -3065,6 +3068,15 @@ static struct db8500_thsens_platform_data db8500_thsens_data = { ...@@ -3065,6 +3068,15 @@ static struct db8500_thsens_platform_data db8500_thsens_data = {
.num_trips = 4, .num_trips = 4,
}; };
static struct mfd_cell common_prcmu_devs[] = {
{
.name = "ux500_wdt",
.platform_data = &db8500_wdt_pdata,
.pdata_size = sizeof(db8500_wdt_pdata),
.id = -1,
},
};
static struct mfd_cell db8500_prcmu_devs[] = { static struct mfd_cell db8500_prcmu_devs[] = {
{ {
.name = "db8500-prcmu-regulators", .name = "db8500-prcmu-regulators",
...@@ -3078,12 +3090,6 @@ static struct mfd_cell db8500_prcmu_devs[] = { ...@@ -3078,12 +3090,6 @@ static struct mfd_cell db8500_prcmu_devs[] = {
.platform_data = &db8500_cpufreq_table, .platform_data = &db8500_cpufreq_table,
.pdata_size = sizeof(db8500_cpufreq_table), .pdata_size = sizeof(db8500_cpufreq_table),
}, },
{
.name = "ux500_wdt",
.platform_data = &db8500_wdt_pdata,
.pdata_size = sizeof(db8500_wdt_pdata),
.id = -1,
},
{ {
.name = "db8500-thermal", .name = "db8500-thermal",
.num_resources = ARRAY_SIZE(db8500_thsens_resources), .num_resources = ARRAY_SIZE(db8500_thsens_resources),
...@@ -3173,13 +3179,25 @@ static int db8500_prcmu_probe(struct platform_device *pdev) ...@@ -3173,13 +3179,25 @@ static int db8500_prcmu_probe(struct platform_device *pdev)
db8500_prcmu_update_cpufreq(); db8500_prcmu_update_cpufreq();
err = mfd_add_devices(&pdev->dev, 0, db8500_prcmu_devs, err = mfd_add_devices(&pdev->dev, 0, common_prcmu_devs,
ARRAY_SIZE(db8500_prcmu_devs), NULL, 0, db8500_irq_domain); ARRAY_SIZE(common_prcmu_devs), NULL, 0, db8500_irq_domain);
if (err) { if (err) {
pr_err("prcmu: Failed to add subdevices\n"); pr_err("prcmu: Failed to add subdevices\n");
return err; return err;
} }
/* TODO: Remove restriction when clk definitions are available. */
if (!of_machine_is_compatible("st-ericsson,u8540")) {
err = mfd_add_devices(&pdev->dev, 0, db8500_prcmu_devs,
ARRAY_SIZE(db8500_prcmu_devs), NULL, 0,
db8500_irq_domain);
if (err) {
mfd_remove_devices(&pdev->dev);
pr_err("prcmu: Failed to add subdevices\n");
goto no_irq_return;
}
}
err = db8500_prcmu_register_ab8500(&pdev->dev, pdata->ab_platdata, err = db8500_prcmu_register_ab8500(&pdev->dev, pdata->ab_platdata,
pdata->ab_irq); pdata->ab_irq);
if (err) { if (err) {
......
...@@ -393,7 +393,7 @@ static int pcap_add_subdev(struct pcap_chip *pcap, ...@@ -393,7 +393,7 @@ static int pcap_add_subdev(struct pcap_chip *pcap,
static int ezx_pcap_remove(struct spi_device *spi) static int ezx_pcap_remove(struct spi_device *spi)
{ {
struct pcap_chip *pcap = dev_get_drvdata(&spi->dev); struct pcap_chip *pcap = spi_get_drvdata(spi);
struct pcap_platform_data *pdata = spi->dev.platform_data; struct pcap_platform_data *pdata = spi->dev.platform_data;
int i, adc_irq; int i, adc_irq;
...@@ -403,7 +403,7 @@ static int ezx_pcap_remove(struct spi_device *spi) ...@@ -403,7 +403,7 @@ static int ezx_pcap_remove(struct spi_device *spi)
/* cleanup ADC */ /* cleanup ADC */
adc_irq = pcap_to_irq(pcap, (pdata->config & PCAP_SECOND_PORT) ? adc_irq = pcap_to_irq(pcap, (pdata->config & PCAP_SECOND_PORT) ?
PCAP_IRQ_ADCDONE2 : PCAP_IRQ_ADCDONE); PCAP_IRQ_ADCDONE2 : PCAP_IRQ_ADCDONE);
free_irq(adc_irq, pcap); devm_free_irq(&spi->dev, adc_irq, pcap);
mutex_lock(&pcap->adc_mutex); mutex_lock(&pcap->adc_mutex);
for (i = 0; i < PCAP_ADC_MAXQ; i++) for (i = 0; i < PCAP_ADC_MAXQ; i++)
kfree(pcap->adc_queue[i]); kfree(pcap->adc_queue[i]);
...@@ -415,8 +415,6 @@ static int ezx_pcap_remove(struct spi_device *spi) ...@@ -415,8 +415,6 @@ static int ezx_pcap_remove(struct spi_device *spi)
destroy_workqueue(pcap->workqueue); destroy_workqueue(pcap->workqueue);
kfree(pcap);
return 0; return 0;
} }
...@@ -431,7 +429,7 @@ static int ezx_pcap_probe(struct spi_device *spi) ...@@ -431,7 +429,7 @@ static int ezx_pcap_probe(struct spi_device *spi)
if (!pdata) if (!pdata)
goto ret; goto ret;
pcap = kzalloc(sizeof(*pcap), GFP_KERNEL); pcap = devm_kzalloc(&spi->dev, sizeof(*pcap), GFP_KERNEL);
if (!pcap) { if (!pcap) {
ret = -ENOMEM; ret = -ENOMEM;
goto ret; goto ret;
...@@ -441,14 +439,14 @@ static int ezx_pcap_probe(struct spi_device *spi) ...@@ -441,14 +439,14 @@ static int ezx_pcap_probe(struct spi_device *spi)
mutex_init(&pcap->adc_mutex); mutex_init(&pcap->adc_mutex);
INIT_WORK(&pcap->isr_work, pcap_isr_work); INIT_WORK(&pcap->isr_work, pcap_isr_work);
INIT_WORK(&pcap->msr_work, pcap_msr_work); INIT_WORK(&pcap->msr_work, pcap_msr_work);
dev_set_drvdata(&spi->dev, pcap); spi_set_drvdata(spi, pcap);
/* setup spi */ /* setup spi */
spi->bits_per_word = 32; spi->bits_per_word = 32;
spi->mode = SPI_MODE_0 | (pdata->config & PCAP_CS_AH ? SPI_CS_HIGH : 0); spi->mode = SPI_MODE_0 | (pdata->config & PCAP_CS_AH ? SPI_CS_HIGH : 0);
ret = spi_setup(spi); ret = spi_setup(spi);
if (ret) if (ret)
goto free_pcap; goto ret;
pcap->spi = spi; pcap->spi = spi;
...@@ -458,7 +456,7 @@ static int ezx_pcap_probe(struct spi_device *spi) ...@@ -458,7 +456,7 @@ static int ezx_pcap_probe(struct spi_device *spi)
if (!pcap->workqueue) { if (!pcap->workqueue) {
ret = -ENOMEM; ret = -ENOMEM;
dev_err(&spi->dev, "can't create pcap thread\n"); dev_err(&spi->dev, "can't create pcap thread\n");
goto free_pcap; goto ret;
} }
/* redirect interrupts to AP, except adcdone2 */ /* redirect interrupts to AP, except adcdone2 */
...@@ -491,7 +489,8 @@ static int ezx_pcap_probe(struct spi_device *spi) ...@@ -491,7 +489,8 @@ static int ezx_pcap_probe(struct spi_device *spi)
adc_irq = pcap_to_irq(pcap, (pdata->config & PCAP_SECOND_PORT) ? adc_irq = pcap_to_irq(pcap, (pdata->config & PCAP_SECOND_PORT) ?
PCAP_IRQ_ADCDONE2 : PCAP_IRQ_ADCDONE); PCAP_IRQ_ADCDONE2 : PCAP_IRQ_ADCDONE);
ret = request_irq(adc_irq, pcap_adc_irq, 0, "ADC", pcap); ret = devm_request_irq(&spi->dev, adc_irq, pcap_adc_irq, 0, "ADC",
pcap);
if (ret) if (ret)
goto free_irqchip; goto free_irqchip;
...@@ -511,14 +510,12 @@ static int ezx_pcap_probe(struct spi_device *spi) ...@@ -511,14 +510,12 @@ static int ezx_pcap_probe(struct spi_device *spi)
remove_subdevs: remove_subdevs:
device_for_each_child(&spi->dev, NULL, pcap_remove_subdev); device_for_each_child(&spi->dev, NULL, pcap_remove_subdev);
/* free_adc: */ /* free_adc: */
free_irq(adc_irq, pcap); devm_free_irq(&spi->dev, adc_irq, pcap);
free_irqchip: free_irqchip:
for (i = pcap->irq_base; i < (pcap->irq_base + PCAP_NIRQS); i++) for (i = pcap->irq_base; i < (pcap->irq_base + PCAP_NIRQS); i++)
irq_set_chip_and_handler(i, NULL, NULL); irq_set_chip_and_handler(i, NULL, NULL);
/* destroy_workqueue: */ /* destroy_workqueue: */
destroy_workqueue(pcap->workqueue); destroy_workqueue(pcap->workqueue);
free_pcap:
kfree(pcap);
ret: ret:
return ret; return ret;
} }
......
...@@ -208,18 +208,7 @@ static struct platform_driver pasic3_driver = { ...@@ -208,18 +208,7 @@ static struct platform_driver pasic3_driver = {
.remove = pasic3_remove, .remove = pasic3_remove,
}; };
static int __init pasic3_base_init(void) module_platform_driver_probe(pasic3_driver, pasic3_probe);
{
return platform_driver_probe(&pasic3_driver, pasic3_probe);
}
static void __exit pasic3_base_exit(void)
{
platform_driver_unregister(&pasic3_driver);
}
module_init(pasic3_base_init);
module_exit(pasic3_base_exit);
MODULE_AUTHOR("Philipp Zabel <philipp.zabel@gmail.com>"); MODULE_AUTHOR("Philipp Zabel <philipp.zabel@gmail.com>");
MODULE_DESCRIPTION("Core driver for HTC PASIC3"); MODULE_DESCRIPTION("Core driver for HTC PASIC3");
......
...@@ -323,7 +323,8 @@ static int intel_msic_init_devices(struct intel_msic *msic) ...@@ -323,7 +323,8 @@ static int intel_msic_init_devices(struct intel_msic *msic)
if (pdata->ocd) { if (pdata->ocd) {
unsigned gpio = pdata->ocd->gpio; unsigned gpio = pdata->ocd->gpio;
ret = gpio_request_one(gpio, GPIOF_IN, "ocd_gpio"); ret = devm_gpio_request_one(&pdev->dev, gpio,
GPIOF_IN, "ocd_gpio");
if (ret) { if (ret) {
dev_err(&pdev->dev, "failed to register OCD GPIO\n"); dev_err(&pdev->dev, "failed to register OCD GPIO\n");
return ret; return ret;
...@@ -332,7 +333,6 @@ static int intel_msic_init_devices(struct intel_msic *msic) ...@@ -332,7 +333,6 @@ static int intel_msic_init_devices(struct intel_msic *msic)
ret = gpio_to_irq(gpio); ret = gpio_to_irq(gpio);
if (ret < 0) { if (ret < 0) {
dev_err(&pdev->dev, "no IRQ number for OCD GPIO\n"); dev_err(&pdev->dev, "no IRQ number for OCD GPIO\n");
gpio_free(gpio);
return ret; return ret;
} }
...@@ -359,8 +359,6 @@ static int intel_msic_init_devices(struct intel_msic *msic) ...@@ -359,8 +359,6 @@ static int intel_msic_init_devices(struct intel_msic *msic)
fail: fail:
mfd_remove_devices(&pdev->dev); mfd_remove_devices(&pdev->dev);
if (pdata->ocd)
gpio_free(pdata->ocd->gpio);
return ret; return ret;
} }
...@@ -368,12 +366,8 @@ static int intel_msic_init_devices(struct intel_msic *msic) ...@@ -368,12 +366,8 @@ static int intel_msic_init_devices(struct intel_msic *msic)
static void intel_msic_remove_devices(struct intel_msic *msic) static void intel_msic_remove_devices(struct intel_msic *msic)
{ {
struct platform_device *pdev = msic->pdev; struct platform_device *pdev = msic->pdev;
struct intel_msic_platform_data *pdata = pdev->dev.platform_data;
mfd_remove_devices(&pdev->dev); mfd_remove_devices(&pdev->dev);
if (pdata->ocd)
gpio_free(pdata->ocd->gpio);
} }
static int intel_msic_probe(struct platform_device *pdev) static int intel_msic_probe(struct platform_device *pdev)
......
...@@ -496,8 +496,8 @@ static int lm3533_device_init(struct lm3533 *lm3533) ...@@ -496,8 +496,8 @@ static int lm3533_device_init(struct lm3533 *lm3533)
dev_set_drvdata(lm3533->dev, lm3533); dev_set_drvdata(lm3533->dev, lm3533);
if (gpio_is_valid(lm3533->gpio_hwen)) { if (gpio_is_valid(lm3533->gpio_hwen)) {
ret = gpio_request_one(lm3533->gpio_hwen, GPIOF_OUT_INIT_LOW, ret = devm_gpio_request_one(lm3533->dev, lm3533->gpio_hwen,
"lm3533-hwen"); GPIOF_OUT_INIT_LOW, "lm3533-hwen");
if (ret < 0) { if (ret < 0) {
dev_err(lm3533->dev, dev_err(lm3533->dev,
"failed to request HWEN GPIO %d\n", "failed to request HWEN GPIO %d\n",
...@@ -528,8 +528,6 @@ static int lm3533_device_init(struct lm3533 *lm3533) ...@@ -528,8 +528,6 @@ static int lm3533_device_init(struct lm3533 *lm3533)
mfd_remove_devices(lm3533->dev); mfd_remove_devices(lm3533->dev);
err_disable: err_disable:
lm3533_disable(lm3533); lm3533_disable(lm3533);
if (gpio_is_valid(lm3533->gpio_hwen))
gpio_free(lm3533->gpio_hwen);
return ret; return ret;
} }
...@@ -542,8 +540,6 @@ static void lm3533_device_exit(struct lm3533 *lm3533) ...@@ -542,8 +540,6 @@ static void lm3533_device_exit(struct lm3533 *lm3533)
mfd_remove_devices(lm3533->dev); mfd_remove_devices(lm3533->dev);
lm3533_disable(lm3533); lm3533_disable(lm3533);
if (gpio_is_valid(lm3533->gpio_hwen))
gpio_free(lm3533->gpio_hwen);
} }
static bool lm3533_readable_register(struct device *dev, unsigned int reg) static bool lm3533_readable_register(struct device *dev, unsigned int reg)
......
...@@ -46,7 +46,7 @@ static struct regmap_config max77686_regmap_config = { ...@@ -46,7 +46,7 @@ static struct regmap_config max77686_regmap_config = {
#ifdef CONFIG_OF #ifdef CONFIG_OF
static struct of_device_id max77686_pmic_dt_match[] = { static struct of_device_id max77686_pmic_dt_match[] = {
{.compatible = "maxim,max77686", .data = 0}, {.compatible = "maxim,max77686", .data = NULL},
{}, {},
}; };
......
...@@ -131,7 +131,7 @@ static int mc13xxx_spi_probe(struct spi_device *spi) ...@@ -131,7 +131,7 @@ static int mc13xxx_spi_probe(struct spi_device *spi)
if (!mc13xxx) if (!mc13xxx)
return -ENOMEM; return -ENOMEM;
dev_set_drvdata(&spi->dev, mc13xxx); spi_set_drvdata(spi, mc13xxx);
spi->mode = SPI_MODE_0 | SPI_CS_HIGH; spi->mode = SPI_MODE_0 | SPI_CS_HIGH;
mc13xxx->dev = &spi->dev; mc13xxx->dev = &spi->dev;
...@@ -144,7 +144,7 @@ static int mc13xxx_spi_probe(struct spi_device *spi) ...@@ -144,7 +144,7 @@ static int mc13xxx_spi_probe(struct spi_device *spi)
ret = PTR_ERR(mc13xxx->regmap); ret = PTR_ERR(mc13xxx->regmap);
dev_err(mc13xxx->dev, "Failed to initialize register map: %d\n", dev_err(mc13xxx->dev, "Failed to initialize register map: %d\n",
ret); ret);
dev_set_drvdata(&spi->dev, NULL); spi_set_drvdata(spi, NULL);
return ret; return ret;
} }
...@@ -164,7 +164,7 @@ static int mc13xxx_spi_probe(struct spi_device *spi) ...@@ -164,7 +164,7 @@ static int mc13xxx_spi_probe(struct spi_device *spi)
static int mc13xxx_spi_remove(struct spi_device *spi) static int mc13xxx_spi_remove(struct spi_device *spi)
{ {
struct mc13xxx *mc13xxx = dev_get_drvdata(&spi->dev); struct mc13xxx *mc13xxx = spi_get_drvdata(spi);
mc13xxx_common_cleanup(mc13xxx); mc13xxx_common_cleanup(mc13xxx);
......
This diff is collapsed.
This diff is collapsed.
extern int omap_tll_enable(void); extern int omap_tll_init(struct usbhs_omap_platform_data *pdata);
extern int omap_tll_disable(void); extern int omap_tll_enable(struct usbhs_omap_platform_data *pdata);
extern int omap_tll_disable(struct usbhs_omap_platform_data *pdata);
...@@ -278,20 +278,20 @@ static void palmas_dt_to_pdata(struct i2c_client *i2c, ...@@ -278,20 +278,20 @@ static void palmas_dt_to_pdata(struct i2c_client *i2c,
int ret; int ret;
u32 prop; u32 prop;
ret = of_property_read_u32(node, "ti,mux_pad1", &prop); ret = of_property_read_u32(node, "ti,mux-pad1", &prop);
if (!ret) { if (!ret) {
pdata->mux_from_pdata = 1; pdata->mux_from_pdata = 1;
pdata->pad1 = prop; pdata->pad1 = prop;
} }
ret = of_property_read_u32(node, "ti,mux_pad2", &prop); ret = of_property_read_u32(node, "ti,mux-pad2", &prop);
if (!ret) { if (!ret) {
pdata->mux_from_pdata = 1; pdata->mux_from_pdata = 1;
pdata->pad2 = prop; pdata->pad2 = prop;
} }
/* The default for this register is all masked */ /* The default for this register is all masked */
ret = of_property_read_u32(node, "ti,power_ctrl", &prop); ret = of_property_read_u32(node, "ti,power-ctrl", &prop);
if (!ret) if (!ret)
pdata->power_ctrl = prop; pdata->power_ctrl = prop;
else else
...@@ -349,6 +349,7 @@ static int palmas_i2c_probe(struct i2c_client *i2c, ...@@ -349,6 +349,7 @@ static int palmas_i2c_probe(struct i2c_client *i2c,
ret = -ENOMEM; ret = -ENOMEM;
goto err; goto err;
} }
palmas->i2c_clients[i]->dev.of_node = of_node_get(node);
} }
palmas->regmap[i] = devm_regmap_init_i2c(palmas->i2c_clients[i], palmas->regmap[i] = devm_regmap_init_i2c(palmas->i2c_clients[i],
&palmas_regmap_config[i]); &palmas_regmap_config[i]);
......
/* /*
* Retu MFD driver * Retu/Tahvo MFD driver
* *
* Copyright (C) 2004, 2005 Nokia Corporation * Copyright (C) 2004, 2005 Nokia Corporation
* *
...@@ -33,7 +33,8 @@ ...@@ -33,7 +33,8 @@
#define RETU_REG_ASICR 0x00 /* ASIC ID and revision */ #define RETU_REG_ASICR 0x00 /* ASIC ID and revision */
#define RETU_REG_ASICR_VILMA (1 << 7) /* Bit indicating Vilma */ #define RETU_REG_ASICR_VILMA (1 << 7) /* Bit indicating Vilma */
#define RETU_REG_IDR 0x01 /* Interrupt ID */ #define RETU_REG_IDR 0x01 /* Interrupt ID */
#define RETU_REG_IMR 0x02 /* Interrupt mask */ #define RETU_REG_IMR 0x02 /* Interrupt mask (Retu) */
#define TAHVO_REG_IMR 0x03 /* Interrupt mask (Tahvo) */
/* Interrupt sources */ /* Interrupt sources */
#define RETU_INT_PWR 0 /* Power button */ #define RETU_INT_PWR 0 /* Power button */
...@@ -84,6 +85,62 @@ static struct regmap_irq_chip retu_irq_chip = { ...@@ -84,6 +85,62 @@ static struct regmap_irq_chip retu_irq_chip = {
/* Retu device registered for the power off. */ /* Retu device registered for the power off. */
static struct retu_dev *retu_pm_power_off; static struct retu_dev *retu_pm_power_off;
static struct resource tahvo_usb_res[] = {
{
.name = "tahvo-usb",
.start = TAHVO_INT_VBUS,
.end = TAHVO_INT_VBUS,
.flags = IORESOURCE_IRQ,
},
};
static struct mfd_cell tahvo_devs[] = {
{
.name = "tahvo-usb",
.resources = tahvo_usb_res,
.num_resources = ARRAY_SIZE(tahvo_usb_res),
},
};
static struct regmap_irq tahvo_irqs[] = {
[TAHVO_INT_VBUS] = {
.mask = 1 << TAHVO_INT_VBUS,
}
};
static struct regmap_irq_chip tahvo_irq_chip = {
.name = "TAHVO",
.irqs = tahvo_irqs,
.num_irqs = ARRAY_SIZE(tahvo_irqs),
.num_regs = 1,
.status_base = RETU_REG_IDR,
.mask_base = TAHVO_REG_IMR,
.ack_base = RETU_REG_IDR,
};
static const struct retu_data {
char *chip_name;
char *companion_name;
struct regmap_irq_chip *irq_chip;
struct mfd_cell *children;
int nchildren;
} retu_data[] = {
[0] = {
.chip_name = "Retu",
.companion_name = "Vilma",
.irq_chip = &retu_irq_chip,
.children = retu_devs,
.nchildren = ARRAY_SIZE(retu_devs),
},
[1] = {
.chip_name = "Tahvo",
.companion_name = "Betty",
.irq_chip = &tahvo_irq_chip,
.children = tahvo_devs,
.nchildren = ARRAY_SIZE(tahvo_devs),
}
};
int retu_read(struct retu_dev *rdev, u8 reg) int retu_read(struct retu_dev *rdev, u8 reg)
{ {
int ret; int ret;
...@@ -173,9 +230,14 @@ static struct regmap_config retu_config = { ...@@ -173,9 +230,14 @@ static struct regmap_config retu_config = {
static int retu_probe(struct i2c_client *i2c, const struct i2c_device_id *id) static int retu_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
{ {
struct retu_data const *rdat;
struct retu_dev *rdev; struct retu_dev *rdev;
int ret; int ret;
if (i2c->addr > ARRAY_SIZE(retu_data))
return -ENODEV;
rdat = &retu_data[i2c->addr - 1];
rdev = devm_kzalloc(&i2c->dev, sizeof(*rdev), GFP_KERNEL); rdev = devm_kzalloc(&i2c->dev, sizeof(*rdev), GFP_KERNEL);
if (rdev == NULL) if (rdev == NULL)
return -ENOMEM; return -ENOMEM;
...@@ -190,25 +252,27 @@ static int retu_probe(struct i2c_client *i2c, const struct i2c_device_id *id) ...@@ -190,25 +252,27 @@ static int retu_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
ret = retu_read(rdev, RETU_REG_ASICR); ret = retu_read(rdev, RETU_REG_ASICR);
if (ret < 0) { if (ret < 0) {
dev_err(rdev->dev, "could not read Retu revision: %d\n", ret); dev_err(rdev->dev, "could not read %s revision: %d\n",
rdat->chip_name, ret);
return ret; return ret;
} }
dev_info(rdev->dev, "Retu%s v%d.%d found\n", dev_info(rdev->dev, "%s%s%s v%d.%d found\n", rdat->chip_name,
(ret & RETU_REG_ASICR_VILMA) ? " & Vilma" : "", (ret & RETU_REG_ASICR_VILMA) ? " & " : "",
(ret & RETU_REG_ASICR_VILMA) ? rdat->companion_name : "",
(ret >> 4) & 0x7, ret & 0xf); (ret >> 4) & 0x7, ret & 0xf);
/* Mask all RETU interrupts. */ /* Mask all interrupts. */
ret = retu_write(rdev, RETU_REG_IMR, 0xffff); ret = retu_write(rdev, rdat->irq_chip->mask_base, 0xffff);
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = regmap_add_irq_chip(rdev->regmap, i2c->irq, IRQF_ONESHOT, -1, ret = regmap_add_irq_chip(rdev->regmap, i2c->irq, IRQF_ONESHOT, -1,
&retu_irq_chip, &rdev->irq_data); rdat->irq_chip, &rdev->irq_data);
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = mfd_add_devices(rdev->dev, -1, retu_devs, ARRAY_SIZE(retu_devs), ret = mfd_add_devices(rdev->dev, -1, rdat->children, rdat->nchildren,
NULL, regmap_irq_chip_get_base(rdev->irq_data), NULL, regmap_irq_chip_get_base(rdev->irq_data),
NULL); NULL);
if (ret < 0) { if (ret < 0) {
...@@ -216,7 +280,7 @@ static int retu_probe(struct i2c_client *i2c, const struct i2c_device_id *id) ...@@ -216,7 +280,7 @@ static int retu_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
return ret; return ret;
} }
if (!pm_power_off) { if (i2c->addr == 1 && !pm_power_off) {
retu_pm_power_off = rdev; retu_pm_power_off = rdev;
pm_power_off = retu_power_off; pm_power_off = retu_power_off;
} }
...@@ -240,6 +304,7 @@ static int retu_remove(struct i2c_client *i2c) ...@@ -240,6 +304,7 @@ static int retu_remove(struct i2c_client *i2c)
static const struct i2c_device_id retu_id[] = { static const struct i2c_device_id retu_id[] = {
{ "retu-mfd", 0 }, { "retu-mfd", 0 },
{ "tahvo-mfd", 0 },
{ } { }
}; };
MODULE_DEVICE_TABLE(i2c, retu_id); MODULE_DEVICE_TABLE(i2c, retu_id);
......
This diff is collapsed.
...@@ -56,6 +56,7 @@ static DEFINE_PCI_DEVICE_TABLE(rtsx_pci_ids) = { ...@@ -56,6 +56,7 @@ static DEFINE_PCI_DEVICE_TABLE(rtsx_pci_ids) = {
{ PCI_DEVICE(0x10EC, 0x5229), PCI_CLASS_OTHERS << 16, 0xFF0000 }, { PCI_DEVICE(0x10EC, 0x5229), PCI_CLASS_OTHERS << 16, 0xFF0000 },
{ PCI_DEVICE(0x10EC, 0x5289), PCI_CLASS_OTHERS << 16, 0xFF0000 }, { PCI_DEVICE(0x10EC, 0x5289), PCI_CLASS_OTHERS << 16, 0xFF0000 },
{ PCI_DEVICE(0x10EC, 0x5227), PCI_CLASS_OTHERS << 16, 0xFF0000 }, { PCI_DEVICE(0x10EC, 0x5227), PCI_CLASS_OTHERS << 16, 0xFF0000 },
{ PCI_DEVICE(0x10EC, 0x5249), PCI_CLASS_OTHERS << 16, 0xFF0000 },
{ 0, } { 0, }
}; };
...@@ -1033,6 +1034,10 @@ static int rtsx_pci_init_chip(struct rtsx_pcr *pcr) ...@@ -1033,6 +1034,10 @@ static int rtsx_pci_init_chip(struct rtsx_pcr *pcr)
case 0x5227: case 0x5227:
rts5227_init_params(pcr); rts5227_init_params(pcr);
break; break;
case 0x5249:
rts5249_init_params(pcr);
break;
} }
dev_dbg(&(pcr->pci->dev), "PID: 0x%04x, IC version: 0x%02x\n", dev_dbg(&(pcr->pci->dev), "PID: 0x%04x, IC version: 0x%02x\n",
...@@ -1138,7 +1143,7 @@ static int rtsx_pci_probe(struct pci_dev *pcidev, ...@@ -1138,7 +1143,7 @@ static int rtsx_pci_probe(struct pci_dev *pcidev,
ret = rtsx_pci_acquire_irq(pcr); ret = rtsx_pci_acquire_irq(pcr);
if (ret < 0) if (ret < 0)
goto free_dma; goto disable_msi;
pci_set_master(pcidev); pci_set_master(pcidev);
synchronize_irq(pcr->irq); synchronize_irq(pcr->irq);
...@@ -1162,7 +1167,9 @@ static int rtsx_pci_probe(struct pci_dev *pcidev, ...@@ -1162,7 +1167,9 @@ static int rtsx_pci_probe(struct pci_dev *pcidev,
disable_irq: disable_irq:
free_irq(pcr->irq, (void *)pcr); free_irq(pcr->irq, (void *)pcr);
free_dma: disable_msi:
if (pcr->msi_en)
pci_disable_msi(pcr->pci);
dma_free_coherent(&(pcr->pci->dev), RTSX_RESV_BUF_LEN, dma_free_coherent(&(pcr->pci->dev), RTSX_RESV_BUF_LEN,
pcr->rtsx_resv_buf, pcr->rtsx_resv_buf_addr); pcr->rtsx_resv_buf, pcr->rtsx_resv_buf_addr);
unmap: unmap:
......
...@@ -32,5 +32,6 @@ void rts5209_init_params(struct rtsx_pcr *pcr); ...@@ -32,5 +32,6 @@ void rts5209_init_params(struct rtsx_pcr *pcr);
void rts5229_init_params(struct rtsx_pcr *pcr); void rts5229_init_params(struct rtsx_pcr *pcr);
void rtl8411_init_params(struct rtsx_pcr *pcr); void rtl8411_init_params(struct rtsx_pcr *pcr);
void rts5227_init_params(struct rtsx_pcr *pcr); void rts5227_init_params(struct rtsx_pcr *pcr);
void rts5249_init_params(struct rtsx_pcr *pcr);
#endif #endif
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -98,17 +98,6 @@ static int sta2x11_mfd_add(struct pci_dev *pdev, gfp_t flags) ...@@ -98,17 +98,6 @@ static int sta2x11_mfd_add(struct pci_dev *pdev, gfp_t flags)
return 0; return 0;
} }
static int mfd_remove(struct pci_dev *pdev)
{
struct sta2x11_mfd *mfd = sta2x11_mfd_find(pdev);
if (!mfd)
return -ENODEV;
list_del(&mfd->list);
kfree(mfd);
return 0;
}
/* This function is exported and is not expected to fail */ /* This function is exported and is not expected to fail */
u32 __sta2x11_mfd_mask(struct pci_dev *pdev, u32 reg, u32 mask, u32 val, u32 __sta2x11_mfd_mask(struct pci_dev *pdev, u32 reg, u32 mask, u32 val,
enum sta2x11_mfd_plat_dev index) enum sta2x11_mfd_plat_dev index)
......
...@@ -75,6 +75,7 @@ static const struct i2c_device_id stmpe_i2c_id[] = { ...@@ -75,6 +75,7 @@ static const struct i2c_device_id stmpe_i2c_id[] = {
{ "stmpe801", STMPE801 }, { "stmpe801", STMPE801 },
{ "stmpe811", STMPE811 }, { "stmpe811", STMPE811 },
{ "stmpe1601", STMPE1601 }, { "stmpe1601", STMPE1601 },
{ "stmpe1801", STMPE1801 },
{ "stmpe2401", STMPE2401 }, { "stmpe2401", STMPE2401 },
{ "stmpe2403", STMPE2403 }, { "stmpe2403", STMPE2403 },
{ } { }
......
...@@ -103,7 +103,7 @@ stmpe_spi_probe(struct spi_device *spi) ...@@ -103,7 +103,7 @@ stmpe_spi_probe(struct spi_device *spi)
static int stmpe_spi_remove(struct spi_device *spi) static int stmpe_spi_remove(struct spi_device *spi)
{ {
struct stmpe *stmpe = dev_get_drvdata(&spi->dev); struct stmpe *stmpe = spi_get_drvdata(spi);
return stmpe_remove(stmpe); return stmpe_remove(stmpe);
} }
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -75,6 +75,11 @@ static int ucb1400_core_probe(struct device *dev) ...@@ -75,6 +75,11 @@ static int ucb1400_core_probe(struct device *dev)
/* GPIO */ /* GPIO */
ucb_gpio.ac97 = ac97; ucb_gpio.ac97 = ac97;
if (pdata) {
ucb_gpio.gpio_setup = pdata->gpio_setup;
ucb_gpio.gpio_teardown = pdata->gpio_teardown;
ucb_gpio.gpio_offset = pdata->gpio_offset;
}
ucb->ucb1400_gpio = platform_device_alloc("ucb1400_gpio", -1); ucb->ucb1400_gpio = platform_device_alloc("ucb1400_gpio", -1);
if (!ucb->ucb1400_gpio) { if (!ucb->ucb1400_gpio) {
err = -ENOMEM; err = -ENOMEM;
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -42,6 +42,7 @@ static int rx51_battery_read_adc(int channel) ...@@ -42,6 +42,7 @@ static int rx51_battery_read_adc(int channel)
req.method = TWL4030_MADC_SW1; req.method = TWL4030_MADC_SW1;
req.func_cb = NULL; req.func_cb = NULL;
req.type = TWL4030_MADC_WAIT; req.type = TWL4030_MADC_WAIT;
req.raw = true;
if (twl4030_madc_conversion(&req) <= 0) if (twl4030_madc_conversion(&req) <= 0)
return -ENODATA; return -ENODATA;
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment