提交 4b781474 编写于 作者: L Linus Torvalds

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

Pull MFD changes from Samuel Ortiz:
 "Besides the usual cleanups, this one brings:

   * Support for 5 new chipsets: Intel's ICH LPC and SCH Centerton,
     ST-E's STAX211, Samsung's MAX77693 and TI's LM3533.

   * Device tree support for the twl6040, tps65910, da9502 and ab8500
     drivers.

   * Fairly big tps56910, ab8500 and db8500 updates.

   * i2c support for mc13xxx.

   * Our regular update for the wm8xxx driver from Mark."

Fix up various conflicts with other trees, largely due to ab5500 removal
etc.

* tag 'mfd-3.5-1' of git://git.kernel.org/pub/scm/linux/kernel/git/sameo/mfd-2.6: (106 commits)
  mfd: Fix build break of max77693 by adding REGMAP_I2C option
  mfd: Fix twl6040 build failure
  mfd: Fix max77693 build failure
  mfd: ab8500-core should depend on MFD_DB8500_PRCMU
  gpio: tps65910: dt: process gpio specific device node info
  mfd: Remove the parsing of dt info for tps65910 gpio
  mfd: Save device node parsed platform data for tps65910 sub devices
  mfd: Add r_select to lm3533 platform data
  gpio: Add Intel Centerton support to gpio-sch
  mfd: Emulate active low IRQs as well as active high IRQs for wm831x
  mfd: Mark two lm3533 zone registers as volatile
  mfd: Fix return type of lm533 attribute is_visible
  mfd: Enable Device Tree support in the ab8500-pwm driver
  mfd: Enable Device Tree support in the ab8500-sysctrl driver
  mfd: Add support for Device Tree to twl6040
  mfd: Register the twl6040 child for the ASoC codec unconditionally
  mfd: Allocate twl6040 IRQ numbers dynamically
  mfd: twl6040 code cleanup in interrupt initialization part
  mfd: Enable ab8500-gpadc driver for Device Tree
  mfd: Prevent unassigned pointer from being used in ab8500-gpadc driver
  ...
What: /sys/bus/i2c/devices/.../output_hvled[n]
Date: April 2012
KernelVersion: 3.5
Contact: Johan Hovold <jhovold@gmail.com>
Description:
Set the controlling backlight device for high-voltage current
sink HVLED[n] (n = 1, 2) (0, 1).
What: /sys/bus/i2c/devices/.../output_lvled[n]
Date: April 2012
KernelVersion: 3.5
Contact: Johan Hovold <jhovold@gmail.com>
Description:
Set the controlling led device for low-voltage current sink
LVLED[n] (n = 1..5) (0..3).
* Dialog DA9052/53 Power Management Integrated Circuit (PMIC)
Required properties:
- compatible : Should be "dlg,da9052", "dlg,da9053-aa",
"dlg,da9053-ab", or "dlg,da9053-bb"
Sub-nodes:
- regulators : Contain the regulator nodes. The DA9052/53 regulators are
bound using their names as listed below:
buck0 : regulator BUCK0
buck1 : regulator BUCK1
buck2 : regulator BUCK2
buck3 : regulator BUCK3
ldo4 : regulator LDO4
ldo5 : regulator LDO5
ldo6 : regulator LDO6
ldo7 : regulator LDO7
ldo8 : regulator LDO8
ldo9 : regulator LDO9
ldo10 : regulator LDO10
ldo11 : regulator LDO11
ldo12 : regulator LDO12
ldo13 : regulator LDO13
The bindings details of individual regulator device can be found in:
Documentation/devicetree/bindings/regulator/regulator.txt
Examples:
i2c@63fc8000 { /* I2C1 */
status = "okay";
pmic: dialog@48 {
compatible = "dlg,da9053-aa";
reg = <0x48>;
regulators {
buck0 {
regulator-min-microvolt = <500000>;
regulator-max-microvolt = <2075000>;
};
buck1 {
regulator-min-microvolt = <500000>;
regulator-max-microvolt = <2075000>;
};
buck2 {
regulator-min-microvolt = <925000>;
regulator-max-microvolt = <2500000>;
};
buck3 {
regulator-min-microvolt = <925000>;
regulator-max-microvolt = <2500000>;
};
};
};
};
TPS65910 Power Management Integrated Circuit
Required properties:
- compatible: "ti,tps65910" or "ti,tps65911"
- reg: I2C slave address
- interrupts: the interrupt outputs of the controller
- #gpio-cells: number of cells to describe a GPIO, this should be 2.
The first cell is the GPIO number.
The second cell is used to specify additional options <unused>.
- gpio-controller: mark the device as a GPIO 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
- regulators: This is the list of child nodes that specify the regulator
initialization data for defined regulators. Not all regulators for the given
device need to be present. The definition for each of these nodes is defined
using the standard binding for regulators found at
Documentation/devicetree/bindings/regulator/regulator.txt.
The valid names for regulators are:
tps65910: vrtc, vio, vdd1, vdd2, vdd3, vdig1, vdig2, vpll, vdac, vaux1,
vaux2, vaux33, vmmc
tps65911: vrtc, vio, vdd1, vdd3, vddctrl, ldo1, ldo2, ldo3, ldo4, ldo5,
ldo6, ldo7, ldo8
Optional properties:
- ti,vmbch-threshold: (tps65911) main battery charged threshold
comparator. (see VMBCH_VSEL in TPS65910 datasheet)
- ti,vmbch2-threshold: (tps65911) main battery discharged threshold
comparator. (see VMBCH_VSEL in TPS65910 datasheet)
- ti,en-gpio-sleep: enable sleep control for gpios
There should be 9 entries here, one for each gpio.
Regulator Optional properties:
- ti,regulator-ext-sleep-control: enable external sleep
control through external inputs [0 (not enabled), 1 (EN1), 2 (EN2) or 4(EN3)]
If this property is not defined, it defaults to 0 (not enabled).
Example:
pmu: tps65910@d2 {
compatible = "ti,tps65910";
reg = <0xd2>;
interrupt-parent = <&intc>;
interrupts = < 0 118 0x04 >;
#gpio-cells = <2>;
gpio-controller;
#interrupt-cells = <2>;
interrupt-controller;
ti,vmbch-threshold = 0;
ti,vmbch2-threshold = 0;
ti,en-gpio-sleep = <0 0 1 0 0 0 0 0 0>;
regulators {
vdd1_reg: vdd1 {
regulator-min-microvolt = < 600000>;
regulator-max-microvolt = <1500000>;
regulator-always-on;
regulator-boot-on;
ti,regulator-ext-sleep-control = <0>;
};
vdd2_reg: vdd2 {
regulator-min-microvolt = < 600000>;
regulator-max-microvolt = <1500000>;
regulator-always-on;
regulator-boot-on;
ti,regulator-ext-sleep-control = <4>;
};
vddctrl_reg: vddctrl {
regulator-min-microvolt = < 600000>;
regulator-max-microvolt = <1400000>;
regulator-always-on;
regulator-boot-on;
ti,regulator-ext-sleep-control = <0>;
};
vio_reg: vio {
regulator-min-microvolt = <1500000>;
regulator-max-microvolt = <1800000>;
regulator-always-on;
regulator-boot-on;
ti,regulator-ext-sleep-control = <1>;
};
ldo1_reg: ldo1 {
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <3300000>;
ti,regulator-ext-sleep-control = <0>;
};
ldo2_reg: ldo2 {
regulator-min-microvolt = <1050000>;
regulator-max-microvolt = <1050000>;
ti,regulator-ext-sleep-control = <0>;
};
ldo3_reg: ldo3 {
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <3300000>;
ti,regulator-ext-sleep-control = <0>;
};
ldo4_reg: ldo4 {
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <3300000>;
regulator-always-on;
ti,regulator-ext-sleep-control = <0>;
};
ldo5_reg: ldo5 {
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <3300000>;
ti,regulator-ext-sleep-control = <0>;
};
ldo6_reg: ldo6 {
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <1200000>;
ti,regulator-ext-sleep-control = <0>;
};
ldo7_reg: ldo7 {
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <1200000>;
regulator-always-on;
regulator-boot-on;
ti,regulator-ext-sleep-control = <1>;
};
ldo8_reg: ldo8 {
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <3300000>;
regulator-always-on;
ti,regulator-ext-sleep-control = <1>;
};
};
};
Texas Instruments TWL6040 family
The TWL6040s are 8-channel high quality low-power audio codecs providing audio
and vibra functionality on OMAP4+ platforms.
They are connected ot the host processor via i2c for commands, McPDM for audio
data and commands.
Required properties:
- compatible : Must be "ti,twl6040";
- reg: must be 0x4b for i2c address
- interrupts: twl6040 has one interrupt line connecteded to the main SoC
- interrupt-parent: The parent interrupt controller
- twl6040,audpwron-gpio: Power on GPIO line for the twl6040
- vio-supply: Regulator for the twl6040 VIO supply
- v2v1-supply: Regulator for the twl6040 V2V1 supply
Optional properties, nodes:
- enable-active-high: To power on the twl6040 during boot.
Vibra functionality
Required properties:
- vddvibl-supply: Regulator for the left vibra motor
- vddvibr-supply: Regulator for the right vibra motor
- vibra { }: Configuration section for vibra parameters containing the following
properties:
- ti,vibldrv-res: Resistance parameter for left driver
- ti,vibrdrv-res: Resistance parameter for right driver
- ti,viblmotor-res: Resistance parameter for left motor
- ti,viblmotor-res: Resistance parameter for right motor
Optional properties within vibra { } section:
- vddvibl_uV: If the vddvibl default voltage need to be changed
- vddvibr_uV: If the vddvibr default voltage need to be changed
Example:
&i2c1 {
twl6040: twl@4b {
compatible = "ti,twl6040";
reg = <0x4b>;
interrupts = <0 119 4>;
interrupt-parent = <&gic>;
twl6040,audpwron-gpio = <&gpio4 31 0>;
vio-supply = <&v1v8>;
v2v1-supply = <&v2v1>;
enable-active-high;
/* regulators for vibra motor */
vddvibl-supply = <&vbat>;
vddvibr-supply = <&vbat>;
vibra {
/* Vibra driver, motor resistance parameters */
ti,vibldrv-res = <8>;
ti,vibrdrv-res = <3>;
ti,viblmotor-res = <10>;
ti,vibrmotor-res = <10>;
};
};
};
......@@ -3382,6 +3382,12 @@ W: http://www.developer.ibm.com/welcome/netfinity/serveraid.html
S: Supported
F: drivers/scsi/ips.*
ICH LPC AND GPIO DRIVER
M: Peter Tyser <ptyser@xes-inc.com>
S: Maintained
F: drivers/mfd/lpc_ich.c
F: drivers/gpio/gpio-ich.c
IDE SUBSYSTEM
M: "David S. Miller" <davem@davemloft.net>
L: linux-ide@vger.kernel.org
......
......@@ -206,7 +206,7 @@ static struct resource ab8500_resources[] = {
};
struct platform_device ab8500_device = {
.name = "ab8500-i2c",
.name = "ab8500-core",
.id = 0,
.dev = {
.platform_data = &ab8500_platdata,
......
/*
* Header file for STMicroelectronics ConneXt (STA2X11) IOHub
*/
#ifndef __ASM_STA2X11_H
#define __ASM_STA2X11_H
#include <linux/pci.h>
/* This needs to be called from the MFD to configure its sub-devices */
struct sta2x11_instance *sta2x11_get_instance(struct pci_dev *pdev);
#endif /* __ASM_STA2X11_H */
......@@ -167,6 +167,14 @@ config GPIO_PXA
help
Say yes here to support the PXA GPIO device
config GPIO_STA2X11
bool "STA2x11/ConneXt GPIO support"
depends on MFD_STA2X11
select GENERIC_IRQ_CHIP
help
Say yes here to support the STA2x11/ConneXt GPIO device.
The GPIO module has 128 GPIO pins with alternate functions.
config GPIO_XILINX
bool "Xilinx GPIO support"
depends on PPC_OF || MICROBLAZE
......@@ -180,13 +188,13 @@ config GPIO_VR41XX
Say yes here to support the NEC VR4100 series General-purpose I/O Uint
config GPIO_SCH
tristate "Intel SCH/TunnelCreek GPIO"
tristate "Intel SCH/TunnelCreek/Centerton GPIO"
depends on PCI && X86
select MFD_CORE
select LPC_SCH
help
Say yes here to support GPIO interface on Intel Poulsbo SCH
or Intel Tunnel Creek processor.
Say yes here to support GPIO interface on Intel Poulsbo SCH,
Intel Tunnel Creek processor or Intel Centerton processor.
The Intel SCH contains a total of 14 GPIO pins. Ten GPIOs are
powered by the core power rail and are turned off during sleep
modes (S3 and higher). The remaining four GPIOs are powered by
......@@ -195,6 +203,22 @@ config GPIO_SCH
system from the Suspend-to-RAM state.
The Intel Tunnel Creek processor has 5 GPIOs powered by the
core power rail and 9 from suspend power supply.
The Intel Centerton processor has a total of 30 GPIO pins.
Twenty-one are powered by the core power rail and 9 from the
suspend power supply.
config GPIO_ICH
tristate "Intel ICH GPIO"
depends on PCI && X86
select MFD_CORE
select LPC_ICH
help
Say yes here to support the GPIO functionality of a number of Intel
ICH-based chipsets. Currently supported devices: ICH6, ICH7, ICH8
ICH9, ICH10, Series 5/3400 (eg Ibex Peak), Series 6/C200 (eg
Cougar Point), NM10 (Tiger Point), and 3100 (Whitmore Lake).
If unsure, say N.
config GPIO_VX855
tristate "VIA VX855/VX875 GPIO"
......
......@@ -19,6 +19,7 @@ obj-$(CONFIG_ARCH_DAVINCI) += gpio-davinci.o
obj-$(CONFIG_GPIO_EM) += gpio-em.o
obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o
obj-$(CONFIG_GPIO_GE_FPGA) += gpio-ge.o
obj-$(CONFIG_GPIO_ICH) += gpio-ich.o
obj-$(CONFIG_GPIO_IT8761E) += gpio-it8761e.o
obj-$(CONFIG_GPIO_JANZ_TTL) += gpio-janz-ttl.o
obj-$(CONFIG_ARCH_KS8695) += gpio-ks8695.o
......@@ -51,6 +52,7 @@ obj-$(CONFIG_PLAT_SAMSUNG) += gpio-samsung.o
obj-$(CONFIG_ARCH_SA1100) += gpio-sa1100.o
obj-$(CONFIG_GPIO_SCH) += gpio-sch.o
obj-$(CONFIG_GPIO_SODAVILLE) += gpio-sodaville.o
obj-$(CONFIG_GPIO_STA2X11) += gpio-sta2x11.o
obj-$(CONFIG_GPIO_STMPE) += gpio-stmpe.o
obj-$(CONFIG_GPIO_SX150X) += gpio-sx150x.o
obj-$(CONFIG_GPIO_TC3589X) += gpio-tc3589x.o
......
/*
* Intel ICH6-10, Series 5 and 6 GPIO driver
*
* Copyright (C) 2010 Extreme Engineering Solutions.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/gpio.h>
#include <linux/platform_device.h>
#include <linux/mfd/lpc_ich.h>
#define DRV_NAME "gpio_ich"
/*
* GPIO register offsets in GPIO I/O space.
* Each chunk of 32 GPIOs is manipulated via its own USE_SELx, IO_SELx, and
* LVLx registers. Logic in the read/write functions takes a register and
* an absolute bit number and determines the proper register offset and bit
* number in that register. For example, to read the value of GPIO bit 50
* the code would access offset ichx_regs[2(=GPIO_LVL)][1(=50/32)],
* bit 18 (50%32).
*/
enum GPIO_REG {
GPIO_USE_SEL = 0,
GPIO_IO_SEL,
GPIO_LVL,
};
static const u8 ichx_regs[3][3] = {
{0x00, 0x30, 0x40}, /* USE_SEL[1-3] offsets */
{0x04, 0x34, 0x44}, /* IO_SEL[1-3] offsets */
{0x0c, 0x38, 0x48}, /* LVL[1-3] offsets */
};
#define ICHX_WRITE(val, reg, base_res) outl(val, (reg) + (base_res)->start)
#define ICHX_READ(reg, base_res) inl((reg) + (base_res)->start)
struct ichx_desc {
/* Max GPIO pins the chipset can have */
uint ngpio;
/* Whether the chipset has GPIO in GPE0_STS in the PM IO region */
bool uses_gpe0;
/* USE_SEL is bogus on some chipsets, eg 3100 */
u32 use_sel_ignore[3];
/* Some chipsets have quirks, let these use their own request/get */
int (*request)(struct gpio_chip *chip, unsigned offset);
int (*get)(struct gpio_chip *chip, unsigned offset);
};
static struct {
spinlock_t lock;
struct platform_device *dev;
struct gpio_chip chip;
struct resource *gpio_base; /* GPIO IO base */
struct resource *pm_base; /* Power Mangagment IO base */
struct ichx_desc *desc; /* Pointer to chipset-specific description */
u32 orig_gpio_ctrl; /* Orig CTRL value, used to restore on exit */
} ichx_priv;
static int modparam_gpiobase = -1; /* dynamic */
module_param_named(gpiobase, modparam_gpiobase, int, 0444);
MODULE_PARM_DESC(gpiobase, "The GPIO number base. -1 means dynamic, "
"which is the default.");
static int ichx_write_bit(int reg, unsigned nr, int val, int verify)
{
unsigned long flags;
u32 data, tmp;
int reg_nr = nr / 32;
int bit = nr & 0x1f;
int ret = 0;
spin_lock_irqsave(&ichx_priv.lock, flags);
data = ICHX_READ(ichx_regs[reg][reg_nr], ichx_priv.gpio_base);
if (val)
data |= 1 << bit;
else
data &= ~(1 << bit);
ICHX_WRITE(data, ichx_regs[reg][reg_nr], ichx_priv.gpio_base);
tmp = ICHX_READ(ichx_regs[reg][reg_nr], ichx_priv.gpio_base);
if (verify && data != tmp)
ret = -EPERM;
spin_unlock_irqrestore(&ichx_priv.lock, flags);
return ret;
}
static int ichx_read_bit(int reg, unsigned nr)
{
unsigned long flags;
u32 data;
int reg_nr = nr / 32;
int bit = nr & 0x1f;
spin_lock_irqsave(&ichx_priv.lock, flags);
data = ICHX_READ(ichx_regs[reg][reg_nr], ichx_priv.gpio_base);
spin_unlock_irqrestore(&ichx_priv.lock, flags);
return data & (1 << bit) ? 1 : 0;
}
static int ichx_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
{
/*
* Try setting pin as an input and verify it worked since many pins
* are output-only.
*/
if (ichx_write_bit(GPIO_IO_SEL, nr, 1, 1))
return -EINVAL;
return 0;
}
static int ichx_gpio_direction_output(struct gpio_chip *gpio, unsigned nr,
int val)
{
/* Set GPIO output value. */
ichx_write_bit(GPIO_LVL, nr, val, 0);
/*
* Try setting pin as an output and verify it worked since many pins
* are input-only.
*/
if (ichx_write_bit(GPIO_IO_SEL, nr, 0, 1))
return -EINVAL;
return 0;
}
static int ichx_gpio_get(struct gpio_chip *chip, unsigned nr)
{
return ichx_read_bit(GPIO_LVL, nr);
}
static int ich6_gpio_get(struct gpio_chip *chip, unsigned nr)
{
unsigned long flags;
u32 data;
/*
* GPI 0 - 15 need to be read from the power management registers on
* a ICH6/3100 bridge.
*/
if (nr < 16) {
if (!ichx_priv.pm_base)
return -ENXIO;
spin_lock_irqsave(&ichx_priv.lock, flags);
/* GPI 0 - 15 are latched, write 1 to clear*/
ICHX_WRITE(1 << (16 + nr), 0, ichx_priv.pm_base);
data = ICHX_READ(0, ichx_priv.pm_base);
spin_unlock_irqrestore(&ichx_priv.lock, flags);
return (data >> 16) & (1 << nr) ? 1 : 0;
} else {
return ichx_gpio_get(chip, nr);
}
}
static int ichx_gpio_request(struct gpio_chip *chip, unsigned nr)
{
/*
* Note we assume the BIOS properly set a bridge's USE value. Some
* chips (eg Intel 3100) have bogus USE values though, so first see if
* the chipset's USE value can be trusted for this specific bit.
* If it can't be trusted, assume that the pin can be used as a GPIO.
*/
if (ichx_priv.desc->use_sel_ignore[nr / 32] & (1 << (nr & 0x1f)))
return 1;
return ichx_read_bit(GPIO_USE_SEL, nr) ? 0 : -ENODEV;
}
static int ich6_gpio_request(struct gpio_chip *chip, unsigned nr)
{
/*
* Fixups for bits 16 and 17 are necessary on the Intel ICH6/3100
* bridge as they are controlled by USE register bits 0 and 1. See
* "Table 704 GPIO_USE_SEL1 register" in the i3100 datasheet for
* additional info.
*/
if (nr == 16 || nr == 17)
nr -= 16;
return ichx_gpio_request(chip, nr);
}
static void ichx_gpio_set(struct gpio_chip *chip, unsigned nr, int val)
{
ichx_write_bit(GPIO_LVL, nr, val, 0);
}
static void __devinit ichx_gpiolib_setup(struct gpio_chip *chip)
{
chip->owner = THIS_MODULE;
chip->label = DRV_NAME;
chip->dev = &ichx_priv.dev->dev;
/* Allow chip-specific overrides of request()/get() */
chip->request = ichx_priv.desc->request ?
ichx_priv.desc->request : ichx_gpio_request;
chip->get = ichx_priv.desc->get ?
ichx_priv.desc->get : ichx_gpio_get;
chip->set = ichx_gpio_set;
chip->direction_input = ichx_gpio_direction_input;
chip->direction_output = ichx_gpio_direction_output;
chip->base = modparam_gpiobase;
chip->ngpio = ichx_priv.desc->ngpio;
chip->can_sleep = 0;
chip->dbg_show = NULL;
}
/* ICH6-based, 631xesb-based */
static struct ichx_desc ich6_desc = {
/* Bridges using the ICH6 controller need fixups for GPIO 0 - 17 */
.request = ich6_gpio_request,
.get = ich6_gpio_get,
/* GPIO 0-15 are read in the GPE0_STS PM register */
.uses_gpe0 = true,
.ngpio = 50,
};
/* Intel 3100 */
static struct ichx_desc i3100_desc = {
/*
* Bits 16,17, 20 of USE_SEL and bit 16 of USE_SEL2 always read 0 on
* the Intel 3100. See "Table 712. GPIO Summary Table" of 3100
* Datasheet for more info.
*/
.use_sel_ignore = {0x00130000, 0x00010000, 0x0},
/* The 3100 needs fixups for GPIO 0 - 17 */
.request = ich6_gpio_request,
.get = ich6_gpio_get,
/* GPIO 0-15 are read in the GPE0_STS PM register */
.uses_gpe0 = true,
.ngpio = 50,
};
/* ICH7 and ICH8-based */
static struct ichx_desc ich7_desc = {
.ngpio = 50,
};
/* ICH9-based */
static struct ichx_desc ich9_desc = {
.ngpio = 61,
};
/* ICH10-based - Consumer/corporate versions have different amount of GPIO */
static struct ichx_desc ich10_cons_desc = {
.ngpio = 61,
};
static struct ichx_desc ich10_corp_desc = {
.ngpio = 72,
};
/* Intel 5 series, 6 series, 3400 series, and C200 series */
static struct ichx_desc intel5_desc = {
.ngpio = 76,
};
static int __devinit ichx_gpio_probe(struct platform_device *pdev)
{
struct resource *res_base, *res_pm;
int err;
struct lpc_ich_info *ich_info = pdev->dev.platform_data;
if (!ich_info)
return -ENODEV;
ichx_priv.dev = pdev;
switch (ich_info->gpio_version) {
case ICH_I3100_GPIO:
ichx_priv.desc = &i3100_desc;
break;
case ICH_V5_GPIO:
ichx_priv.desc = &intel5_desc;
break;
case ICH_V6_GPIO:
ichx_priv.desc = &ich6_desc;
break;
case ICH_V7_GPIO:
ichx_priv.desc = &ich7_desc;
break;
case ICH_V9_GPIO:
ichx_priv.desc = &ich9_desc;
break;
case ICH_V10CORP_GPIO:
ichx_priv.desc = &ich10_corp_desc;
break;
case ICH_V10CONS_GPIO:
ichx_priv.desc = &ich10_cons_desc;
break;
default:
return -ENODEV;
}
res_base = platform_get_resource(pdev, IORESOURCE_IO, ICH_RES_GPIO);
if (!res_base || !res_base->start || !res_base->end)
return -ENODEV;
if (!request_region(res_base->start, resource_size(res_base),
pdev->name))
return -EBUSY;
ichx_priv.gpio_base = res_base;
/*
* If necessary, determine the I/O address of ACPI/power management
* registers which are needed to read the the GPE0 register for GPI pins
* 0 - 15 on some chipsets.
*/
if (!ichx_priv.desc->uses_gpe0)
goto init;
res_pm = platform_get_resource(pdev, IORESOURCE_IO, ICH_RES_GPE0);
if (!res_pm) {
pr_warn("ACPI BAR is unavailable, GPI 0 - 15 unavailable\n");
goto init;
}
if (!request_region(res_pm->start, resource_size(res_pm),
pdev->name)) {
pr_warn("ACPI BAR is busy, GPI 0 - 15 unavailable\n");
goto init;
}
ichx_priv.pm_base = res_pm;
init:
ichx_gpiolib_setup(&ichx_priv.chip);
err = gpiochip_add(&ichx_priv.chip);
if (err) {
pr_err("Failed to register GPIOs\n");
goto add_err;
}
pr_info("GPIO from %d to %d on %s\n", ichx_priv.chip.base,
ichx_priv.chip.base + ichx_priv.chip.ngpio - 1, DRV_NAME);
return 0;
add_err:
release_region(ichx_priv.gpio_base->start,
resource_size(ichx_priv.gpio_base));
if (ichx_priv.pm_base)
release_region(ichx_priv.pm_base->start,
resource_size(ichx_priv.pm_base));
return err;
}
static int __devexit ichx_gpio_remove(struct platform_device *pdev)
{
int err;
err = gpiochip_remove(&ichx_priv.chip);
if (err) {
dev_err(&pdev->dev, "%s failed, %d\n",
"gpiochip_remove()", err);
return err;
}
release_region(ichx_priv.gpio_base->start,
resource_size(ichx_priv.gpio_base));
if (ichx_priv.pm_base)
release_region(ichx_priv.pm_base->start,
resource_size(ichx_priv.pm_base));
return 0;
}
static struct platform_driver ichx_gpio_driver = {
.driver = {
.owner = THIS_MODULE,
.name = DRV_NAME,
},
.probe = ichx_gpio_probe,
.remove = __devexit_p(ichx_gpio_remove),
};
module_platform_driver(ichx_gpio_driver);
MODULE_AUTHOR("Peter Tyser <ptyser@xes-inc.com>");
MODULE_DESCRIPTION("GPIO interface for Intel ICH series");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:"DRV_NAME);
......@@ -232,6 +232,14 @@ static int __devinit sch_gpio_probe(struct platform_device *pdev)
sch_gpio_resume.ngpio = 9;
break;
case PCI_DEVICE_ID_INTEL_CENTERTON_ILB:
sch_gpio_core.base = 0;
sch_gpio_core.ngpio = 21;
sch_gpio_resume.base = 21;
sch_gpio_resume.ngpio = 9;
break;
default:
return -ENODEV;
}
......
/*
* STMicroelectronics ConneXt (STA2X11) GPIO driver
*
* Copyright 2012 ST Microelectronics (Alessandro Rubini)
* Based on gpio-ml-ioh.c, Copyright 2010 OKI Semiconductors Ltd.
* Also based on previous sta2x11 work, Copyright 2011 Wind River Systems, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/pci.h>
#include <linux/platform_device.h>
#include <linux/mfd/sta2x11-mfd.h>
struct gsta_regs {
u32 dat; /* 0x00 */
u32 dats;
u32 datc;
u32 pdis;
u32 dir; /* 0x10 */
u32 dirs;
u32 dirc;
u32 unused_1c;
u32 afsela; /* 0x20 */
u32 unused_24[7];
u32 rimsc; /* 0x40 */
u32 fimsc;
u32 is;
u32 ic;
};
struct gsta_gpio {
spinlock_t lock;
struct device *dev;
void __iomem *reg_base;
struct gsta_regs __iomem *regs[GSTA_NR_BLOCKS];
struct gpio_chip gpio;
int irq_base;
/* FIXME: save the whole config here (AF, ...) */
unsigned irq_type[GSTA_NR_GPIO];
};
static inline struct gsta_regs __iomem *__regs(struct gsta_gpio *chip, int nr)
{
return chip->regs[nr / GSTA_GPIO_PER_BLOCK];
}
static inline u32 __bit(int nr)
{
return 1U << (nr % GSTA_GPIO_PER_BLOCK);
}
/*
* gpio methods
*/
static void gsta_gpio_set(struct gpio_chip *gpio, unsigned nr, int val)
{
struct gsta_gpio *chip = container_of(gpio, struct gsta_gpio, gpio);
struct gsta_regs __iomem *regs = __regs(chip, nr);
u32 bit = __bit(nr);
if (val)
writel(bit, &regs->dats);
else
writel(bit, &regs->datc);
}
static int gsta_gpio_get(struct gpio_chip *gpio, unsigned nr)
{
struct gsta_gpio *chip = container_of(gpio, struct gsta_gpio, gpio);
struct gsta_regs __iomem *regs = __regs(chip, nr);
u32 bit = __bit(nr);
return readl(&regs->dat) & bit;
}
static int gsta_gpio_direction_output(struct gpio_chip *gpio, unsigned nr,
int val)
{
struct gsta_gpio *chip = container_of(gpio, struct gsta_gpio, gpio);
struct gsta_regs __iomem *regs = __regs(chip, nr);
u32 bit = __bit(nr);
writel(bit, &regs->dirs);
/* Data register after direction, otherwise pullup/down is selected */
if (val)
writel(bit, &regs->dats);
else
writel(bit, &regs->datc);
return 0;
}
static int gsta_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
{
struct gsta_gpio *chip = container_of(gpio, struct gsta_gpio, gpio);
struct gsta_regs __iomem *regs = __regs(chip, nr);
u32 bit = __bit(nr);
writel(bit, &regs->dirc);
return 0;
}
static int gsta_gpio_to_irq(struct gpio_chip *gpio, unsigned offset)
{
struct gsta_gpio *chip = container_of(gpio, struct gsta_gpio, gpio);
return chip->irq_base + offset;
}
static void gsta_gpio_setup(struct gsta_gpio *chip) /* called from probe */
{
struct gpio_chip *gpio = &chip->gpio;
/*
* ARCH_NR_GPIOS is currently 256 and dynamic allocation starts
* from the end. However, for compatibility, we need the first
* ConneXt device to start from gpio 0: it's the main chipset
* on most boards so documents and drivers assume gpio0..gpio127
*/
static int gpio_base;
gpio->label = dev_name(chip->dev);
gpio->owner = THIS_MODULE;
gpio->direction_input = gsta_gpio_direction_input;
gpio->get = gsta_gpio_get;
gpio->direction_output = gsta_gpio_direction_output;
gpio->set = gsta_gpio_set;
gpio->dbg_show = NULL;
gpio->base = gpio_base;
gpio->ngpio = GSTA_NR_GPIO;
gpio->can_sleep = 0;
gpio->to_irq = gsta_gpio_to_irq;
/*
* After the first device, turn to dynamic gpio numbers.
* For example, with ARCH_NR_GPIOS = 256 we can fit two cards
*/
if (!gpio_base)
gpio_base = -1;
}
/*
* Special method: alternate functions and pullup/pulldown. This is only
* invoked on startup to configure gpio's according to platform data.
* FIXME : this functionality shall be managed (and exported to other drivers)
* via the pin control subsystem.
*/
static void gsta_set_config(struct gsta_gpio *chip, int nr, unsigned cfg)
{
struct gsta_regs __iomem *regs = __regs(chip, nr);
unsigned long flags;
u32 bit = __bit(nr);
u32 val;
int err = 0;
pr_info("%s: %p %i %i\n", __func__, chip, nr, cfg);
if (cfg == PINMUX_TYPE_NONE)
return;
/* Alternate function or not? */
spin_lock_irqsave(&chip->lock, flags);
val = readl(&regs->afsela);
if (cfg == PINMUX_TYPE_FUNCTION)
val |= bit;
else
val &= ~bit;
writel(val | bit, &regs->afsela);
if (cfg == PINMUX_TYPE_FUNCTION) {
spin_unlock_irqrestore(&chip->lock, flags);
return;
}
/* not alternate function: set details */
switch (cfg) {
case PINMUX_TYPE_OUTPUT_LOW:
writel(bit, &regs->dirs);
writel(bit, &regs->datc);
break;
case PINMUX_TYPE_OUTPUT_HIGH:
writel(bit, &regs->dirs);
writel(bit, &regs->dats);
break;
case PINMUX_TYPE_INPUT:
writel(bit, &regs->dirc);
val = readl(&regs->pdis) | bit;
writel(val, &regs->pdis);
break;
case PINMUX_TYPE_INPUT_PULLUP:
writel(bit, &regs->dirc);
val = readl(&regs->pdis) & ~bit;
writel(val, &regs->pdis);
writel(bit, &regs->dats);
break;
case PINMUX_TYPE_INPUT_PULLDOWN:
writel(bit, &regs->dirc);
val = readl(&regs->pdis) & ~bit;
writel(val, &regs->pdis);
writel(bit, &regs->datc);
break;
default:
err = 1;
}
spin_unlock_irqrestore(&chip->lock, flags);
if (err)
pr_err("%s: chip %p, pin %i, cfg %i is invalid\n",
__func__, chip, nr, cfg);
}
/*
* Irq methods
*/
static void gsta_irq_disable(struct irq_data *data)
{
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data);
struct gsta_gpio *chip = gc->private;
int nr = data->irq - chip->irq_base;
struct gsta_regs __iomem *regs = __regs(chip, nr);
u32 bit = __bit(nr);
u32 val;
unsigned long flags;
spin_lock_irqsave(&chip->lock, flags);
if (chip->irq_type[nr] & IRQ_TYPE_EDGE_RISING) {
val = readl(&regs->rimsc) & ~bit;
writel(val, &regs->rimsc);
}
if (chip->irq_type[nr] & IRQ_TYPE_EDGE_FALLING) {
val = readl(&regs->fimsc) & ~bit;
writel(val, &regs->fimsc);
}
spin_unlock_irqrestore(&chip->lock, flags);
return;
}
static void gsta_irq_enable(struct irq_data *data)
{
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data);
struct gsta_gpio *chip = gc->private;
int nr = data->irq - chip->irq_base;
struct gsta_regs __iomem *regs = __regs(chip, nr);
u32 bit = __bit(nr);
u32 val;
int type;
unsigned long flags;
type = chip->irq_type[nr];
spin_lock_irqsave(&chip->lock, flags);
val = readl(&regs->rimsc);
if (type & IRQ_TYPE_EDGE_RISING)
writel(val | bit, &regs->rimsc);
else
writel(val & ~bit, &regs->rimsc);
val = readl(&regs->rimsc);
if (type & IRQ_TYPE_EDGE_FALLING)
writel(val | bit, &regs->fimsc);
else
writel(val & ~bit, &regs->fimsc);
spin_unlock_irqrestore(&chip->lock, flags);
return;
}
static int gsta_irq_type(struct irq_data *d, unsigned int type)
{
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
struct gsta_gpio *chip = gc->private;
int nr = d->irq - chip->irq_base;
/* We only support edge interrupts */
if (!(type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))) {
pr_debug("%s: unsupported type 0x%x\n", __func__, type);
return -EINVAL;
}
chip->irq_type[nr] = type; /* used for enable/disable */
gsta_irq_enable(d);
return 0;
}
static irqreturn_t gsta_gpio_handler(int irq, void *dev_id)
{
struct gsta_gpio *chip = dev_id;
struct gsta_regs __iomem *regs;
u32 is;
int i, nr, base;
irqreturn_t ret = IRQ_NONE;
for (i = 0; i < GSTA_NR_BLOCKS; i++) {
regs = chip->regs[i];
base = chip->irq_base + i * GSTA_GPIO_PER_BLOCK;
while ((is = readl(&regs->is))) {
nr = __ffs(is);
irq = base + nr;
generic_handle_irq(irq);
writel(1 << nr, &regs->ic);
ret = IRQ_HANDLED;
}
}
return ret;
}
static __devinit void gsta_alloc_irq_chip(struct gsta_gpio *chip)
{
struct irq_chip_generic *gc;
struct irq_chip_type *ct;
gc = irq_alloc_generic_chip(KBUILD_MODNAME, 1, chip->irq_base,
chip->reg_base, handle_simple_irq);
gc->private = chip;
ct = gc->chip_types;
ct->chip.irq_set_type = gsta_irq_type;
ct->chip.irq_disable = gsta_irq_disable;
ct->chip.irq_enable = gsta_irq_enable;
/* FIXME: this makes at most 32 interrupts. Request 0 by now */
irq_setup_generic_chip(gc, 0 /* IRQ_MSK(GSTA_GPIO_PER_BLOCK) */, 0,
IRQ_NOREQUEST | IRQ_NOPROBE, 0);
/* Set up all all 128 interrupts: code from setup_generic_chip */
{
struct irq_chip_type *ct = gc->chip_types;
int i, j;
for (j = 0; j < GSTA_NR_GPIO; j++) {
i = chip->irq_base + j;
irq_set_chip_and_handler(i, &ct->chip, ct->handler);
irq_set_chip_data(i, gc);
irq_modify_status(i, IRQ_NOREQUEST | IRQ_NOPROBE, 0);
}
gc->irq_cnt = i - gc->irq_base;
}
}
/* The platform device used here is instantiated by the MFD device */
static int __devinit gsta_probe(struct platform_device *dev)
{
int i, err;
struct pci_dev *pdev;
struct sta2x11_gpio_pdata *gpio_pdata;
struct gsta_gpio *chip;
struct resource *res;
pdev = *(struct pci_dev **)(dev->dev.platform_data);
gpio_pdata = dev_get_platdata(&pdev->dev);
if (gpio_pdata == NULL)
dev_err(&dev->dev, "no gpio config\n");
pr_debug("gpio config: %p\n", gpio_pdata);
res = platform_get_resource(dev, IORESOURCE_MEM, 0);
chip = devm_kzalloc(&dev->dev, sizeof(*chip), GFP_KERNEL);
chip->dev = &dev->dev;
chip->reg_base = devm_request_and_ioremap(&dev->dev, res);
for (i = 0; i < GSTA_NR_BLOCKS; i++) {
chip->regs[i] = chip->reg_base + i * 4096;
/* disable all irqs */
writel(0, &chip->regs[i]->rimsc);
writel(0, &chip->regs[i]->fimsc);
writel(~0, &chip->regs[i]->ic);
}
spin_lock_init(&chip->lock);
gsta_gpio_setup(chip);
for (i = 0; i < GSTA_NR_GPIO; i++)
gsta_set_config(chip, i, gpio_pdata->pinconfig[i]);
/* 384 was used in previous code: be compatible for other drivers */
err = irq_alloc_descs(-1, 384, GSTA_NR_GPIO, NUMA_NO_NODE);
if (err < 0) {
dev_warn(&dev->dev, "sta2x11 gpio: Can't get irq base (%i)\n",
-err);
return err;
}
chip->irq_base = err;
gsta_alloc_irq_chip(chip);
err = request_irq(pdev->irq, gsta_gpio_handler,
IRQF_SHARED, KBUILD_MODNAME, chip);
if (err < 0) {
dev_err(&dev->dev, "sta2x11 gpio: Can't request irq (%i)\n",
-err);
goto err_free_descs;
}
err = gpiochip_add(&chip->gpio);
if (err < 0) {
dev_err(&dev->dev, "sta2x11 gpio: Can't register (%i)\n",
-err);
goto err_free_irq;
}
platform_set_drvdata(dev, chip);
return 0;
err_free_irq:
free_irq(pdev->irq, chip);
err_free_descs:
irq_free_descs(chip->irq_base, GSTA_NR_GPIO);
return err;
}
static struct platform_driver sta2x11_gpio_platform_driver = {
.driver = {
.name = "sta2x11-gpio",
.owner = THIS_MODULE,
},
.probe = gsta_probe,
};
module_platform_driver(sta2x11_gpio_platform_driver);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("sta2x11_gpio GPIO driver");
......@@ -18,14 +18,27 @@
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <linux/mfd/tps65910.h>
#include <linux/of_device.h>
struct tps65910_gpio {
struct gpio_chip gpio_chip;
struct tps65910 *tps65910;
};
static inline struct tps65910_gpio *to_tps65910_gpio(struct gpio_chip *chip)
{
return container_of(chip, struct tps65910_gpio, gpio_chip);
}
static int tps65910_gpio_get(struct gpio_chip *gc, unsigned offset)
{
struct tps65910 *tps65910 = container_of(gc, struct tps65910, gpio);
uint8_t val;
struct tps65910_gpio *tps65910_gpio = to_tps65910_gpio(gc);
struct tps65910 *tps65910 = tps65910_gpio->tps65910;
unsigned int val;
tps65910->read(tps65910, TPS65910_GPIO0 + offset, 1, &val);
tps65910_reg_read(tps65910, TPS65910_GPIO0 + offset, &val);
if (val & GPIO_STS_MASK)
return 1;
......@@ -36,83 +49,170 @@ static int tps65910_gpio_get(struct gpio_chip *gc, unsigned offset)
static void tps65910_gpio_set(struct gpio_chip *gc, unsigned offset,
int value)
{
struct tps65910 *tps65910 = container_of(gc, struct tps65910, gpio);
struct tps65910_gpio *tps65910_gpio = to_tps65910_gpio(gc);
struct tps65910 *tps65910 = tps65910_gpio->tps65910;
if (value)
tps65910_set_bits(tps65910, TPS65910_GPIO0 + offset,
tps65910_reg_set_bits(tps65910, TPS65910_GPIO0 + offset,
GPIO_SET_MASK);
else
tps65910_clear_bits(tps65910, TPS65910_GPIO0 + offset,
tps65910_reg_clear_bits(tps65910, TPS65910_GPIO0 + offset,
GPIO_SET_MASK);
}
static int tps65910_gpio_output(struct gpio_chip *gc, unsigned offset,
int value)
{
struct tps65910 *tps65910 = container_of(gc, struct tps65910, gpio);
struct tps65910_gpio *tps65910_gpio = to_tps65910_gpio(gc);
struct tps65910 *tps65910 = tps65910_gpio->tps65910;
/* Set the initial value */
tps65910_gpio_set(gc, offset, value);
return tps65910_set_bits(tps65910, TPS65910_GPIO0 + offset,
return tps65910_reg_set_bits(tps65910, TPS65910_GPIO0 + offset,
GPIO_CFG_MASK);
}
static int tps65910_gpio_input(struct gpio_chip *gc, unsigned offset)
{
struct tps65910 *tps65910 = container_of(gc, struct tps65910, gpio);
struct tps65910_gpio *tps65910_gpio = to_tps65910_gpio(gc);
struct tps65910 *tps65910 = tps65910_gpio->tps65910;
return tps65910_clear_bits(tps65910, TPS65910_GPIO0 + offset,
return tps65910_reg_clear_bits(tps65910, TPS65910_GPIO0 + offset,
GPIO_CFG_MASK);
}
void tps65910_gpio_init(struct tps65910 *tps65910, int gpio_base)
#ifdef CONFIG_OF
static struct tps65910_board *tps65910_parse_dt_for_gpio(struct device *dev,
struct tps65910 *tps65910, int chip_ngpio)
{
struct tps65910_board *tps65910_board = tps65910->of_plat_data;
unsigned int prop_array[TPS6591X_MAX_NUM_GPIO];
int ngpio = min(chip_ngpio, TPS6591X_MAX_NUM_GPIO);
int ret;
struct tps65910_board *board_data;
int idx;
tps65910_board->gpio_base = -1;
ret = of_property_read_u32_array(tps65910->dev->of_node,
"ti,en-gpio-sleep", prop_array, ngpio);
if (ret < 0) {
dev_dbg(dev, "ti,en-gpio-sleep not specified\n");
return tps65910_board;
}
if (!gpio_base)
return;
for (idx = 0; idx < ngpio; idx++)
tps65910_board->en_gpio_sleep[idx] = (prop_array[idx] != 0);
tps65910->gpio.owner = THIS_MODULE;
tps65910->gpio.label = tps65910->i2c_client->name;
tps65910->gpio.dev = tps65910->dev;
tps65910->gpio.base = gpio_base;
return tps65910_board;
}
#else
static struct tps65910_board *tps65910_parse_dt_for_gpio(struct device *dev,
struct tps65910 *tps65910, int chip_ngpio)
{
return NULL;
}
#endif
static int __devinit tps65910_gpio_probe(struct platform_device *pdev)
{
struct tps65910 *tps65910 = dev_get_drvdata(pdev->dev.parent);
struct tps65910_board *pdata = dev_get_platdata(tps65910->dev);
struct tps65910_gpio *tps65910_gpio;
int ret;
int i;
tps65910_gpio = devm_kzalloc(&pdev->dev,
sizeof(*tps65910_gpio), GFP_KERNEL);
if (!tps65910_gpio) {
dev_err(&pdev->dev, "Could not allocate tps65910_gpio\n");
return -ENOMEM;
}
tps65910_gpio->tps65910 = tps65910;
tps65910_gpio->gpio_chip.owner = THIS_MODULE;
tps65910_gpio->gpio_chip.label = tps65910->i2c_client->name;
switch(tps65910_chip_id(tps65910)) {
case TPS65910:
tps65910->gpio.ngpio = TPS65910_NUM_GPIO;
tps65910_gpio->gpio_chip.ngpio = TPS65910_NUM_GPIO;
break;
case TPS65911:
tps65910->gpio.ngpio = TPS65911_NUM_GPIO;
tps65910_gpio->gpio_chip.ngpio = TPS65911_NUM_GPIO;
break;
default:
return;
return -EINVAL;
}
tps65910_gpio->gpio_chip.can_sleep = 1;
tps65910_gpio->gpio_chip.direction_input = tps65910_gpio_input;
tps65910_gpio->gpio_chip.direction_output = tps65910_gpio_output;
tps65910_gpio->gpio_chip.set = tps65910_gpio_set;
tps65910_gpio->gpio_chip.get = tps65910_gpio_get;
tps65910_gpio->gpio_chip.dev = &pdev->dev;
if (pdata && pdata->gpio_base)
tps65910_gpio->gpio_chip.base = pdata->gpio_base;
else
tps65910_gpio->gpio_chip.base = -1;
if (!pdata && tps65910->dev->of_node)
pdata = tps65910_parse_dt_for_gpio(&pdev->dev, tps65910,
tps65910_gpio->gpio_chip.ngpio);
if (!pdata)
goto skip_init;
/* Configure sleep control for gpios if provided */
for (i = 0; i < tps65910_gpio->gpio_chip.ngpio; ++i) {
if (!pdata->en_gpio_sleep[i])
continue;
ret = tps65910_reg_set_bits(tps65910,
TPS65910_GPIO0 + i, GPIO_SLEEP_MASK);
if (ret < 0)
dev_warn(tps65910->dev,
"GPIO Sleep setting failed with err %d\n", ret);
}
tps65910->gpio.can_sleep = 1;
tps65910->gpio.direction_input = tps65910_gpio_input;
tps65910->gpio.direction_output = tps65910_gpio_output;
tps65910->gpio.set = tps65910_gpio_set;
tps65910->gpio.get = tps65910_gpio_get;
/* Configure sleep control for gpios */
board_data = dev_get_platdata(tps65910->dev);
if (board_data) {
int i;
for (i = 0; i < tps65910->gpio.ngpio; ++i) {
if (board_data->en_gpio_sleep[i]) {
ret = tps65910_set_bits(tps65910,
TPS65910_GPIO0 + i, GPIO_SLEEP_MASK);
if (ret < 0)
dev_warn(tps65910->dev,
"GPIO Sleep setting failed\n");
}
}
skip_init:
ret = gpiochip_add(&tps65910_gpio->gpio_chip);
if (ret < 0) {
dev_err(&pdev->dev, "Could not register gpiochip, %d\n", ret);
return ret;
}
ret = gpiochip_add(&tps65910->gpio);
platform_set_drvdata(pdev, tps65910_gpio);
return ret;
}
static int __devexit tps65910_gpio_remove(struct platform_device *pdev)
{
struct tps65910_gpio *tps65910_gpio = platform_get_drvdata(pdev);
if (ret)
dev_warn(tps65910->dev, "GPIO registration failed: %d\n", ret);
return gpiochip_remove(&tps65910_gpio->gpio_chip);
}
static struct platform_driver tps65910_gpio_driver = {
.driver.name = "tps65910-gpio",
.driver.owner = THIS_MODULE,
.probe = tps65910_gpio_probe,
.remove = __devexit_p(tps65910_gpio_remove),
};
static int __init tps65910_gpio_init(void)
{
return platform_driver_register(&tps65910_gpio_driver);
}
subsys_initcall(tps65910_gpio_init);
static void __exit tps65910_gpio_exit(void)
{
platform_driver_unregister(&tps65910_gpio_driver);
}
module_exit(tps65910_gpio_exit);
MODULE_AUTHOR("Graeme Gregory <gg@slimlogic.co.uk>");
MODULE_AUTHOR("Jorge Eduardo Candelaria jedu@slimlogic.co.uk>");
MODULE_DESCRIPTION("GPIO interface for TPS65910/TPS6511 PMICs");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:tps65910-gpio");
......@@ -102,10 +102,8 @@ static int wm831x_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
struct wm831x_gpio *wm831x_gpio = to_wm831x_gpio(chip);
struct wm831x *wm831x = wm831x_gpio->wm831x;
if (!wm831x->irq_base)
return -EINVAL;
return wm831x->irq_base + WM831X_IRQ_GPIO_1 + offset;
return irq_create_mapping(wm831x->irq_domain,
WM831X_IRQ_GPIO_1 + offset);
}
static int wm831x_gpio_set_debounce(struct gpio_chip *chip, unsigned offset,
......
......@@ -73,7 +73,7 @@ static int __devinit wm831x_on_probe(struct platform_device *pdev)
{
struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
struct wm831x_on *wm831x_on;
int irq = platform_get_irq(pdev, 0);
int irq = wm831x_irq(wm831x, platform_get_irq(pdev, 0));
int ret;
wm831x_on = kzalloc(sizeof(struct wm831x_on), GFP_KERNEL);
......
......@@ -260,15 +260,16 @@ static __devinit int wm831x_ts_probe(struct platform_device *pdev)
* If we have a direct IRQ use it, otherwise use the interrupt
* from the WM831x IRQ controller.
*/
wm831x_ts->data_irq = wm831x_irq(wm831x,
platform_get_irq_byname(pdev,
"TCHDATA"));
if (pdata && pdata->data_irq)
wm831x_ts->data_irq = pdata->data_irq;
else
wm831x_ts->data_irq = platform_get_irq_byname(pdev, "TCHDATA");
wm831x_ts->pd_irq = wm831x_irq(wm831x,
platform_get_irq_byname(pdev, "TCHPD"));
if (pdata && pdata->pd_irq)
wm831x_ts->pd_irq = pdata->pd_irq;
else
wm831x_ts->pd_irq = platform_get_irq_byname(pdev, "TCHPD");
if (pdata)
wm831x_ts->pressure = pdata->pressure;
......
......@@ -106,6 +106,19 @@ config UCB1400_CORE
To compile this driver as a module, choose M here: the
module will be called ucb1400_core.
config MFD_LM3533
tristate "LM3533 Lighting Power chip"
depends on I2C
select MFD_CORE
select REGMAP_I2C
help
Say yes here to enable support for National Semiconductor / TI
LM3533 Lighting Power chips.
This driver provides common support for accessing the device;
additional drivers must be enabled in order to use the LED,
backlight or ambient-light-sensor functionality of the device.
config TPS6105X
tristate "TPS61050/61052 Boost Converters"
depends on I2C
......@@ -177,8 +190,8 @@ config MFD_TPS65910
bool "TPS65910 Power Management chip"
depends on I2C=y && GPIOLIB
select MFD_CORE
select GPIO_TPS65910
select REGMAP_I2C
select IRQ_DOMAIN
help
if you say yes here you get support for the TPS65910 series of
Power Management chips.
......@@ -409,6 +422,19 @@ config PMIC_ADP5520
individual components like LCD backlight, LEDs, GPIOs and Kepad
under the corresponding menus.
config MFD_MAX77693
bool "Maxim Semiconductor MAX77693 PMIC Support"
depends on I2C=y && GENERIC_HARDIRQS
select MFD_CORE
select REGMAP_I2C
help
Say yes here to support for Maxim Semiconductor MAX77693.
This is a companion Power Management IC with Flash, Haptic, Charger,
and MUIC(Micro USB Interface Controller) controls on chip.
This driver provides common support for accessing the device;
additional drivers must be enabled in order to use the functionality
of the device.
config MFD_MAX8925
bool "Maxim Semiconductor MAX8925 PMIC Support"
depends on I2C=y && GENERIC_HARDIRQS
......@@ -454,9 +480,9 @@ config MFD_S5M_CORE
of the device
config MFD_WM8400
tristate "Support Wolfson Microelectronics WM8400"
bool "Support Wolfson Microelectronics WM8400"
select MFD_CORE
depends on I2C
depends on I2C=y
select REGMAP_I2C
help
Support for the Wolfson Microelecronics WM8400 PMIC and audio
......@@ -473,6 +499,7 @@ config MFD_WM831X_I2C
select MFD_CORE
select MFD_WM831X
select REGMAP_I2C
select IRQ_DOMAIN
depends on I2C=y && GENERIC_HARDIRQS
help
Support for the Wolfson Microelecronics WM831x and WM832x PMICs
......@@ -485,6 +512,7 @@ config MFD_WM831X_SPI
select MFD_CORE
select MFD_WM831X
select REGMAP_SPI
select IRQ_DOMAIN
depends on SPI_MASTER && GENERIC_HARDIRQS
help
Support for the Wolfson Microelecronics WM831x and WM832x PMICs
......@@ -597,17 +625,32 @@ config MFD_MC13783
tristate
config MFD_MC13XXX
tristate "Support Freescale MC13783 and MC13892"
depends on SPI_MASTER
tristate
depends on SPI_MASTER || I2C
select MFD_CORE
select MFD_MC13783
help
Support for the Freescale (Atlas) PMIC and audio CODECs
MC13783 and MC13892.
This driver provides common support for accessing the device,
Enable support for the Freescale MC13783 and MC13892 PMICs.
This driver provides common support for accessing the device,
additional drivers must be enabled in order to use the
functionality of the device.
config MFD_MC13XXX_SPI
tristate "Freescale MC13783 and MC13892 SPI interface"
depends on SPI_MASTER
select REGMAP_SPI
select MFD_MC13XXX
help
Select this if your MC13xxx is connected via an SPI bus.
config MFD_MC13XXX_I2C
tristate "Freescale MC13892 I2C interface"
depends on I2C
select REGMAP_I2C
select MFD_MC13XXX
help
Select this if your MC13xxx is connected via an I2C bus.
config ABX500_CORE
bool "ST-Ericsson ABX500 Mixed Signal Circuit register functions"
default y if ARCH_U300 || ARCH_U8500
......@@ -651,7 +694,7 @@ config EZX_PCAP
config AB8500_CORE
bool "ST-Ericsson AB8500 Mixed Signal Power Management chip"
depends on GENERIC_HARDIRQS && ABX500_CORE
depends on GENERIC_HARDIRQS && ABX500_CORE && MFD_DB8500_PRCMU
select MFD_CORE
help
Select this option to enable access to AB8500 power management
......@@ -722,6 +765,16 @@ config LPC_SCH
LPC bridge function of the Intel SCH provides support for
System Management Bus and General Purpose I/O.
config LPC_ICH
tristate "Intel ICH LPC"
depends on PCI
select MFD_CORE
help
The LPC bridge function of the Intel ICH provides support for
many functional units. This driver provides needed support for
other drivers to control these functions, currently GPIO and
watchdog.
config MFD_RDC321X
tristate "Support for RDC-R321x southbridge"
select MFD_CORE
......@@ -854,6 +907,11 @@ config MFD_RC5T583
Additional drivers must be enabled in order to use the
different functionality of the device.
config MFD_STA2X11
bool "STA2X11 multi function device support"
depends on STA2X11
select MFD_CORE
config MFD_ANATOP
bool "Support for Freescale i.MX on-chip ANATOP controller"
depends on SOC_IMX6Q
......
......@@ -15,6 +15,7 @@ obj-$(CONFIG_MFD_DAVINCI_VOICECODEC) += davinci_voicecodec.o
obj-$(CONFIG_MFD_DM355EVM_MSP) += dm355evm_msp.o
obj-$(CONFIG_MFD_TI_SSP) += ti-ssp.o
obj-$(CONFIG_MFD_STA2X11) += sta2x11-mfd.o
obj-$(CONFIG_MFD_STMPE) += stmpe.o
obj-$(CONFIG_STMPE_I2C) += stmpe-i2c.o
obj-$(CONFIG_STMPE_SPI) += stmpe-spi.o
......@@ -54,6 +55,8 @@ obj-$(CONFIG_TWL6030_PWM) += twl6030-pwm.o
obj-$(CONFIG_TWL6040_CORE) += twl6040-core.o twl6040-irq.o
obj-$(CONFIG_MFD_MC13XXX) += mc13xxx-core.o
obj-$(CONFIG_MFD_MC13XXX_SPI) += mc13xxx-spi.o
obj-$(CONFIG_MFD_MC13XXX_I2C) += mc13xxx-i2c.o
obj-$(CONFIG_MFD_CORE) += mfd-core.o
......@@ -75,6 +78,7 @@ obj-$(CONFIG_PMIC_DA9052) += da9052-core.o
obj-$(CONFIG_MFD_DA9052_SPI) += da9052-spi.o
obj-$(CONFIG_MFD_DA9052_I2C) += da9052-i2c.o
obj-$(CONFIG_MFD_MAX77693) += max77693.o max77693-irq.o
max8925-objs := max8925-core.o max8925-i2c.o
obj-$(CONFIG_MFD_MAX8925) += max8925.o
obj-$(CONFIG_MFD_MAX8997) += max8997.o max8997-irq.o
......@@ -87,15 +91,15 @@ obj-$(CONFIG_PCF50633_GPIO) += pcf50633-gpio.o
obj-$(CONFIG_ABX500_CORE) += abx500-core.o
obj-$(CONFIG_AB3100_CORE) += ab3100-core.o
obj-$(CONFIG_AB3100_OTP) += ab3100-otp.o
obj-$(CONFIG_AB8500_CORE) += ab8500-core.o ab8500-sysctrl.o
obj-$(CONFIG_AB8500_DEBUG) += ab8500-debugfs.o
obj-$(CONFIG_AB8500_GPADC) += ab8500-gpadc.o
obj-$(CONFIG_MFD_DB8500_PRCMU) += db8500-prcmu.o
# ab8500-i2c need to come after db8500-prcmu (which provides the channel)
obj-$(CONFIG_AB8500_I2C_CORE) += ab8500-i2c.o
# ab8500-core need to come after db8500-prcmu (which provides the channel)
obj-$(CONFIG_AB8500_CORE) += ab8500-core.o ab8500-sysctrl.o
obj-$(CONFIG_MFD_TIMBERDALE) += timberdale.o
obj-$(CONFIG_PMIC_ADP5520) += adp5520.o
obj-$(CONFIG_LPC_SCH) += lpc_sch.o
obj-$(CONFIG_LPC_ICH) += lpc_ich.o
obj-$(CONFIG_MFD_RDC321X) += rdc321x-southbridge.o
obj-$(CONFIG_MFD_JANZ_CMODIO) += janz-cmodio.o
obj-$(CONFIG_MFD_JZ4740_ADC) += jz4740-adc.o
......
......@@ -18,7 +18,10 @@
#include <linux/mfd/core.h>
#include <linux/mfd/abx500.h>
#include <linux/mfd/abx500/ab8500.h>
#include <linux/mfd/dbx500-prcmu.h>
#include <linux/regulator/ab8500.h>
#include <linux/of.h>
#include <linux/of_device.h>
/*
* Interrupt register offsets
......@@ -91,12 +94,24 @@
#define AB8500_IT_MASK23_REG 0x56
#define AB8500_IT_MASK24_REG 0x57
/*
* latch hierarchy registers
*/
#define AB8500_IT_LATCHHIER1_REG 0x60
#define AB8500_IT_LATCHHIER2_REG 0x61
#define AB8500_IT_LATCHHIER3_REG 0x62
#define AB8500_IT_LATCHHIER_NUM 3
#define AB8500_REV_REG 0x80
#define AB8500_IC_NAME_REG 0x82
#define AB8500_SWITCH_OFF_STATUS 0x00
#define AB8500_TURN_ON_STATUS 0x00
static bool no_bm; /* No battery management */
module_param(no_bm, bool, S_IRUGO);
#define AB9540_MODEM_CTRL2_REG 0x23
#define AB9540_MODEM_CTRL2_SWDBBRSTN_BIT BIT(2)
......@@ -125,6 +140,41 @@ static const char ab8500_version_str[][7] = {
[AB8500_VERSION_AB8540] = "AB8540",
};
static int ab8500_i2c_write(struct ab8500 *ab8500, u16 addr, u8 data)
{
int ret;
ret = prcmu_abb_write((u8)(addr >> 8), (u8)(addr & 0xFF), &data, 1);
if (ret < 0)
dev_err(ab8500->dev, "prcmu i2c error %d\n", ret);
return ret;
}
static int ab8500_i2c_write_masked(struct ab8500 *ab8500, u16 addr, u8 mask,
u8 data)
{
int ret;
ret = prcmu_abb_write_masked((u8)(addr >> 8), (u8)(addr & 0xFF), &data,
&mask, 1);
if (ret < 0)
dev_err(ab8500->dev, "prcmu i2c error %d\n", ret);
return ret;
}
static int ab8500_i2c_read(struct ab8500 *ab8500, u16 addr)
{
int ret;
u8 data;
ret = prcmu_abb_read((u8)(addr >> 8), (u8)(addr & 0xFF), &data, 1);
if (ret < 0) {
dev_err(ab8500->dev, "prcmu i2c error %d\n", ret);
return ret;
}
return (int)data;
}
static int ab8500_get_chip_id(struct device *dev)
{
struct ab8500 *ab8500;
......@@ -161,9 +211,13 @@ static int set_register_interruptible(struct ab8500 *ab8500, u8 bank,
static int ab8500_set_register(struct device *dev, u8 bank,
u8 reg, u8 value)
{
int ret;
struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
return set_register_interruptible(ab8500, bank, reg, value);
atomic_inc(&ab8500->transfer_ongoing);
ret = set_register_interruptible(ab8500, bank, reg, value);
atomic_dec(&ab8500->transfer_ongoing);
return ret;
}
static int get_register_interruptible(struct ab8500 *ab8500, u8 bank,
......@@ -192,9 +246,13 @@ static int get_register_interruptible(struct ab8500 *ab8500, u8 bank,
static int ab8500_get_register(struct device *dev, u8 bank,
u8 reg, u8 *value)
{
int ret;
struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
return get_register_interruptible(ab8500, bank, reg, value);
atomic_inc(&ab8500->transfer_ongoing);
ret = get_register_interruptible(ab8500, bank, reg, value);
atomic_dec(&ab8500->transfer_ongoing);
return ret;
}
static int mask_and_set_register_interruptible(struct ab8500 *ab8500, u8 bank,
......@@ -241,11 +299,14 @@ static int mask_and_set_register_interruptible(struct ab8500 *ab8500, u8 bank,
static int ab8500_mask_and_set_register(struct device *dev,
u8 bank, u8 reg, u8 bitmask, u8 bitvalues)
{
int ret;
struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
return mask_and_set_register_interruptible(ab8500, bank, reg,
bitmask, bitvalues);
atomic_inc(&ab8500->transfer_ongoing);
ret= mask_and_set_register_interruptible(ab8500, bank, reg,
bitmask, bitvalues);
atomic_dec(&ab8500->transfer_ongoing);
return ret;
}
static struct abx500_ops ab8500_ops = {
......@@ -264,6 +325,7 @@ static void ab8500_irq_lock(struct irq_data *data)
struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
mutex_lock(&ab8500->irq_lock);
atomic_inc(&ab8500->transfer_ongoing);
}
static void ab8500_irq_sync_unlock(struct irq_data *data)
......@@ -292,7 +354,7 @@ static void ab8500_irq_sync_unlock(struct irq_data *data)
reg = AB8500_IT_MASK1_REG + ab8500->irq_reg_offset[i];
set_register_interruptible(ab8500, AB8500_INTERRUPT, reg, new);
}
atomic_dec(&ab8500->transfer_ongoing);
mutex_unlock(&ab8500->irq_lock);
}
......@@ -325,6 +387,90 @@ static struct irq_chip ab8500_irq_chip = {
.irq_unmask = ab8500_irq_unmask,
};
static int ab8500_handle_hierarchical_line(struct ab8500 *ab8500,
int latch_offset, u8 latch_val)
{
int int_bit = __ffs(latch_val);
int line, i;
do {
int_bit = __ffs(latch_val);
for (i = 0; i < ab8500->mask_size; i++)
if (ab8500->irq_reg_offset[i] == latch_offset)
break;
if (i >= ab8500->mask_size) {
dev_err(ab8500->dev, "Register offset 0x%2x not declared\n",
latch_offset);
return -ENXIO;
}
line = (i << 3) + int_bit;
latch_val &= ~(1 << int_bit);
handle_nested_irq(ab8500->irq_base + line);
} while (latch_val);
return 0;
}
static int ab8500_handle_hierarchical_latch(struct ab8500 *ab8500,
int hier_offset, u8 hier_val)
{
int latch_bit, status;
u8 latch_offset, latch_val;
do {
latch_bit = __ffs(hier_val);
latch_offset = (hier_offset << 3) + latch_bit;
/* Fix inconsistent ITFromLatch25 bit mapping... */
if (unlikely(latch_offset == 17))
latch_offset = 24;
status = get_register_interruptible(ab8500,
AB8500_INTERRUPT,
AB8500_IT_LATCH1_REG + latch_offset,
&latch_val);
if (status < 0 || latch_val == 0)
goto discard;
status = ab8500_handle_hierarchical_line(ab8500,
latch_offset, latch_val);
if (status < 0)
return status;
discard:
hier_val &= ~(1 << latch_bit);
} while (hier_val);
return 0;
}
static irqreturn_t ab8500_hierarchical_irq(int irq, void *dev)
{
struct ab8500 *ab8500 = dev;
u8 i;
dev_vdbg(ab8500->dev, "interrupt\n");
/* Hierarchical interrupt version */
for (i = 0; i < AB8500_IT_LATCHHIER_NUM; i++) {
int status;
u8 hier_val;
status = get_register_interruptible(ab8500, AB8500_INTERRUPT,
AB8500_IT_LATCHHIER1_REG + i, &hier_val);
if (status < 0 || hier_val == 0)
continue;
status = ab8500_handle_hierarchical_latch(ab8500, i, hier_val);
if (status < 0)
break;
}
return IRQ_HANDLED;
}
static irqreturn_t ab8500_irq(int irq, void *dev)
{
struct ab8500 *ab8500 = dev;
......@@ -332,6 +478,8 @@ static irqreturn_t ab8500_irq(int irq, void *dev)
dev_vdbg(ab8500->dev, "interrupt\n");
atomic_inc(&ab8500->transfer_ongoing);
for (i = 0; i < ab8500->mask_size; i++) {
int regoffset = ab8500->irq_reg_offset[i];
int status;
......@@ -355,9 +503,10 @@ static irqreturn_t ab8500_irq(int irq, void *dev)
handle_nested_irq(ab8500->irq_base + line);
value &= ~(1 << bit);
} while (value);
}
atomic_dec(&ab8500->transfer_ongoing);
return IRQ_HANDLED;
}
......@@ -411,6 +560,14 @@ static void ab8500_irq_remove(struct ab8500 *ab8500)
}
}
int ab8500_suspend(struct ab8500 *ab8500)
{
if (atomic_read(&ab8500->transfer_ongoing))
return -EINVAL;
else
return 0;
}
/* AB8500 GPIO Resources */
static struct resource __devinitdata ab8500_gpio_resources[] = {
{
......@@ -744,6 +901,39 @@ static struct resource __devinitdata ab8500_usb_resources[] = {
},
};
static struct resource __devinitdata ab8505_iddet_resources[] = {
{
.name = "KeyDeglitch",
.start = AB8505_INT_KEYDEGLITCH,
.end = AB8505_INT_KEYDEGLITCH,
.flags = IORESOURCE_IRQ,
},
{
.name = "KP",
.start = AB8505_INT_KP,
.end = AB8505_INT_KP,
.flags = IORESOURCE_IRQ,
},
{
.name = "IKP",
.start = AB8505_INT_IKP,
.end = AB8505_INT_IKP,
.flags = IORESOURCE_IRQ,
},
{
.name = "IKR",
.start = AB8505_INT_IKR,
.end = AB8505_INT_IKR,
.flags = IORESOURCE_IRQ,
},
{
.name = "KeyStuck",
.start = AB8505_INT_KEYSTUCK,
.end = AB8505_INT_KEYSTUCK,
.flags = IORESOURCE_IRQ,
},
};
static struct resource __devinitdata ab8500_temp_resources[] = {
{
.name = "AB8500_TEMP_WARM",
......@@ -777,35 +967,11 @@ static struct mfd_cell __devinitdata abx500_common_devs[] = {
.num_resources = ARRAY_SIZE(ab8500_rtc_resources),
.resources = ab8500_rtc_resources,
},
{
.name = "ab8500-charger",
.num_resources = ARRAY_SIZE(ab8500_charger_resources),
.resources = ab8500_charger_resources,
},
{
.name = "ab8500-btemp",
.num_resources = ARRAY_SIZE(ab8500_btemp_resources),
.resources = ab8500_btemp_resources,
},
{
.name = "ab8500-fg",
.num_resources = ARRAY_SIZE(ab8500_fg_resources),
.resources = ab8500_fg_resources,
},
{
.name = "ab8500-chargalg",
.num_resources = ARRAY_SIZE(ab8500_chargalg_resources),
.resources = ab8500_chargalg_resources,
},
{
.name = "ab8500-acc-det",
.num_resources = ARRAY_SIZE(ab8500_av_acc_detect_resources),
.resources = ab8500_av_acc_detect_resources,
},
{
.name = "ab8500-codec",
},
{
.name = "ab8500-poweron-key",
.num_resources = ARRAY_SIZE(ab8500_poweronkey_db_resources),
......@@ -834,6 +1000,29 @@ static struct mfd_cell __devinitdata abx500_common_devs[] = {
},
};
static struct mfd_cell __devinitdata ab8500_bm_devs[] = {
{
.name = "ab8500-charger",
.num_resources = ARRAY_SIZE(ab8500_charger_resources),
.resources = ab8500_charger_resources,
},
{
.name = "ab8500-btemp",
.num_resources = ARRAY_SIZE(ab8500_btemp_resources),
.resources = ab8500_btemp_resources,
},
{
.name = "ab8500-fg",
.num_resources = ARRAY_SIZE(ab8500_fg_resources),
.resources = ab8500_fg_resources,
},
{
.name = "ab8500-chargalg",
.num_resources = ARRAY_SIZE(ab8500_chargalg_resources),
.resources = ab8500_chargalg_resources,
},
};
static struct mfd_cell __devinitdata ab8500_devs[] = {
{
.name = "ab8500-gpio",
......@@ -845,6 +1034,9 @@ static struct mfd_cell __devinitdata ab8500_devs[] = {
.num_resources = ARRAY_SIZE(ab8500_usb_resources),
.resources = ab8500_usb_resources,
},
{
.name = "ab8500-codec",
},
};
static struct mfd_cell __devinitdata ab9540_devs[] = {
......@@ -858,6 +1050,18 @@ static struct mfd_cell __devinitdata ab9540_devs[] = {
.num_resources = ARRAY_SIZE(ab8500_usb_resources),
.resources = ab8500_usb_resources,
},
{
.name = "ab9540-codec",
},
};
/* Device list common to ab9540 and ab8505 */
static struct mfd_cell __devinitdata ab9540_ab8505_devs[] = {
{
.name = "ab-iddet",
.num_resources = ARRAY_SIZE(ab8505_iddet_resources),
.resources = ab8505_iddet_resources,
},
};
static ssize_t show_chip_id(struct device *dev,
......@@ -1003,18 +1207,66 @@ static struct attribute_group ab9540_attr_group = {
.attrs = ab9540_sysfs_entries,
};
int __devinit ab8500_init(struct ab8500 *ab8500, enum ab8500_version version)
static const struct of_device_id ab8500_match[] = {
{
.compatible = "stericsson,ab8500",
.data = (void *)AB8500_VERSION_AB8500,
},
{},
};
static int __devinit ab8500_probe(struct platform_device *pdev)
{
struct ab8500_platform_data *plat = dev_get_platdata(ab8500->dev);
struct ab8500_platform_data *plat = dev_get_platdata(&pdev->dev);
const struct platform_device_id *platid = platform_get_device_id(pdev);
enum ab8500_version version = AB8500_VERSION_UNDEFINED;
struct device_node *np = pdev->dev.of_node;
struct ab8500 *ab8500;
struct resource *resource;
int ret;
int i;
u8 value;
ab8500 = kzalloc(sizeof *ab8500, GFP_KERNEL);
if (!ab8500)
return -ENOMEM;
if (plat)
ab8500->irq_base = plat->irq_base;
else if (np)
ret = of_property_read_u32(np, "stericsson,irq-base", &ab8500->irq_base);
if (!ab8500->irq_base) {
dev_info(&pdev->dev, "couldn't find irq-base\n");
ret = -EINVAL;
goto out_free_ab8500;
}
ab8500->dev = &pdev->dev;
resource = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!resource) {
ret = -ENODEV;
goto out_free_ab8500;
}
ab8500->irq = resource->start;
ab8500->read = ab8500_i2c_read;
ab8500->write = ab8500_i2c_write;
ab8500->write_masked = ab8500_i2c_write_masked;
mutex_init(&ab8500->lock);
mutex_init(&ab8500->irq_lock);
atomic_set(&ab8500->transfer_ongoing, 0);
platform_set_drvdata(pdev, ab8500);
if (platid)
version = platid->driver_data;
else if (np)
version = (unsigned int)
of_match_device(ab8500_match, &pdev->dev)->data;
if (version != AB8500_VERSION_UNDEFINED)
ab8500->version = version;
......@@ -1022,7 +1274,7 @@ int __devinit ab8500_init(struct ab8500 *ab8500, enum ab8500_version version)
ret = get_register_interruptible(ab8500, AB8500_MISC,
AB8500_IC_NAME_REG, &value);
if (ret < 0)
return ret;
goto out_free_ab8500;
ab8500->version = value;
}
......@@ -1030,7 +1282,7 @@ int __devinit ab8500_init(struct ab8500 *ab8500, enum ab8500_version version)
ret = get_register_interruptible(ab8500, AB8500_MISC,
AB8500_REV_REG, &value);
if (ret < 0)
return ret;
goto out_free_ab8500;
ab8500->chip_id = value;
......@@ -1105,30 +1357,57 @@ int __devinit ab8500_init(struct ab8500 *ab8500, enum ab8500_version version)
if (ret)
goto out_freeoldmask;
ret = request_threaded_irq(ab8500->irq, NULL, ab8500_irq,
IRQF_ONESHOT | IRQF_NO_SUSPEND,
"ab8500", ab8500);
/* Activate this feature only in ab9540 */
/* till tests are done on ab8500 1p2 or later*/
if (is_ab9540(ab8500))
ret = request_threaded_irq(ab8500->irq, NULL,
ab8500_hierarchical_irq,
IRQF_ONESHOT | IRQF_NO_SUSPEND,
"ab8500", ab8500);
else
ret = request_threaded_irq(ab8500->irq, NULL,
ab8500_irq,
IRQF_ONESHOT | IRQF_NO_SUSPEND,
"ab8500", ab8500);
if (ret)
goto out_removeirq;
}
ret = mfd_add_devices(ab8500->dev, 0, abx500_common_devs,
ARRAY_SIZE(abx500_common_devs), NULL,
ab8500->irq_base);
if (!np) {
ret = mfd_add_devices(ab8500->dev, 0, abx500_common_devs,
ARRAY_SIZE(abx500_common_devs), NULL,
ab8500->irq_base);
if (ret)
goto out_freeirq;
if (ret)
goto out_freeirq;
if (is_ab9540(ab8500))
ret = mfd_add_devices(ab8500->dev, 0, ab9540_devs,
ARRAY_SIZE(ab9540_devs), NULL,
ab8500->irq_base);
else
ret = mfd_add_devices(ab8500->dev, 0, ab8500_devs,
ARRAY_SIZE(ab8500_devs), NULL,
ab8500->irq_base);
if (ret)
goto out_freeirq;
if (is_ab9540(ab8500))
ret = mfd_add_devices(ab8500->dev, 0, ab9540_devs,
ARRAY_SIZE(ab9540_devs), NULL,
ab8500->irq_base);
else
ret = mfd_add_devices(ab8500->dev, 0, ab8500_devs,
ARRAY_SIZE(ab9540_devs), NULL,
ab8500->irq_base);
if (ret)
goto out_freeirq;
if (is_ab9540(ab8500) || is_ab8505(ab8500))
ret = mfd_add_devices(ab8500->dev, 0, ab9540_ab8505_devs,
ARRAY_SIZE(ab9540_ab8505_devs), NULL,
ab8500->irq_base);
if (ret)
goto out_freeirq;
}
if (!no_bm) {
/* Add battery management devices */
ret = mfd_add_devices(ab8500->dev, 0, ab8500_bm_devs,
ARRAY_SIZE(ab8500_bm_devs), NULL,
ab8500->irq_base);
if (ret)
dev_err(ab8500->dev, "error adding bm devices\n");
}
if (is_ab9540(ab8500))
ret = sysfs_create_group(&ab8500->dev->kobj,
......@@ -1151,12 +1430,16 @@ int __devinit ab8500_init(struct ab8500 *ab8500, enum ab8500_version version)
kfree(ab8500->oldmask);
out_freemask:
kfree(ab8500->mask);
out_free_ab8500:
kfree(ab8500);
return ret;
}
int __devexit ab8500_exit(struct ab8500 *ab8500)
static int __devexit ab8500_remove(struct platform_device *pdev)
{
struct ab8500 *ab8500 = platform_get_drvdata(pdev);
if (is_ab9540(ab8500))
sysfs_remove_group(&ab8500->dev->kobj, &ab9540_attr_group);
else
......@@ -1168,10 +1451,42 @@ int __devexit ab8500_exit(struct ab8500 *ab8500)
}
kfree(ab8500->oldmask);
kfree(ab8500->mask);
kfree(ab8500);
return 0;
}
static const struct platform_device_id ab8500_id[] = {
{ "ab8500-core", AB8500_VERSION_AB8500 },
{ "ab8505-i2c", AB8500_VERSION_AB8505 },
{ "ab9540-i2c", AB8500_VERSION_AB9540 },
{ "ab8540-i2c", AB8500_VERSION_AB8540 },
{ }
};
static struct platform_driver ab8500_core_driver = {
.driver = {
.name = "ab8500-core",
.owner = THIS_MODULE,
.of_match_table = ab8500_match,
},
.probe = ab8500_probe,
.remove = __devexit_p(ab8500_remove),
.id_table = ab8500_id,
};
static int __init ab8500_core_init(void)
{
return platform_driver_register(&ab8500_core_driver);
}
static void __exit ab8500_core_exit(void)
{
platform_driver_unregister(&ab8500_core_driver);
}
arch_initcall(ab8500_core_init);
module_exit(ab8500_core_exit);
MODULE_AUTHOR("Mattias Wallin, Srinidhi Kasagar, Rabin Vincent");
MODULE_DESCRIPTION("AB8500 MFD core");
MODULE_LICENSE("GPL v2");
......@@ -608,10 +608,16 @@ static int __devexit ab8500_debug_remove(struct platform_device *plf)
return 0;
}
static const struct of_device_id ab8500_debug_match[] = {
{ .compatible = "stericsson,ab8500-debug", },
{}
};
static struct platform_driver ab8500_debug_driver = {
.driver = {
.name = "ab8500-debug",
.owner = THIS_MODULE,
.of_match_table = ab8500_debug_match,
},
.probe = ab8500_debug_probe,
.remove = __devexit_p(ab8500_debug_remove)
......
......@@ -584,7 +584,7 @@ static int __devinit ab8500_gpadc_probe(struct platform_device *pdev)
gpadc->irq = platform_get_irq_byname(pdev, "SW_CONV_END");
if (gpadc->irq < 0) {
dev_err(gpadc->dev, "failed to get platform irq-%d\n",
dev_err(&pdev->dev, "failed to get platform irq-%d\n",
gpadc->irq);
ret = gpadc->irq;
goto fail;
......@@ -648,12 +648,18 @@ static int __devexit ab8500_gpadc_remove(struct platform_device *pdev)
return 0;
}
static const struct of_device_id ab8500_gpadc_match[] = {
{ .compatible = "stericsson,ab8500-gpadc", },
{}
};
static struct platform_driver ab8500_gpadc_driver = {
.probe = ab8500_gpadc_probe,
.remove = __devexit_p(ab8500_gpadc_remove),
.driver = {
.name = "ab8500-gpadc",
.owner = THIS_MODULE,
.of_match_table = ab8500_gpadc_match,
},
};
......
/*
* Copyright (C) ST-Ericsson SA 2010
* Author: Mattias Wallin <mattias.wallin@stericsson.com> for ST-Ericsson.
* License Terms: GNU General Public License v2
* This file was based on drivers/mfd/ab8500-spi.c
*/
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/mfd/abx500/ab8500.h>
#include <linux/mfd/dbx500-prcmu.h>
static int ab8500_i2c_write(struct ab8500 *ab8500, u16 addr, u8 data)
{
int ret;
ret = prcmu_abb_write((u8)(addr >> 8), (u8)(addr & 0xFF), &data, 1);
if (ret < 0)
dev_err(ab8500->dev, "prcmu i2c error %d\n", ret);
return ret;
}
static int ab8500_i2c_write_masked(struct ab8500 *ab8500, u16 addr, u8 mask,
u8 data)
{
int ret;
ret = prcmu_abb_write_masked((u8)(addr >> 8), (u8)(addr & 0xFF), &data,
&mask, 1);
if (ret < 0)
dev_err(ab8500->dev, "prcmu i2c error %d\n", ret);
return ret;
}
static int ab8500_i2c_read(struct ab8500 *ab8500, u16 addr)
{
int ret;
u8 data;
ret = prcmu_abb_read((u8)(addr >> 8), (u8)(addr & 0xFF), &data, 1);
if (ret < 0) {
dev_err(ab8500->dev, "prcmu i2c error %d\n", ret);
return ret;
}
return (int)data;
}
static int __devinit ab8500_i2c_probe(struct platform_device *plf)
{
const struct platform_device_id *platid = platform_get_device_id(plf);
struct ab8500 *ab8500;
struct resource *resource;
int ret;
ab8500 = kzalloc(sizeof *ab8500, GFP_KERNEL);
if (!ab8500)
return -ENOMEM;
ab8500->dev = &plf->dev;
resource = platform_get_resource(plf, IORESOURCE_IRQ, 0);
if (!resource) {
kfree(ab8500);
return -ENODEV;
}
ab8500->irq = resource->start;
ab8500->read = ab8500_i2c_read;
ab8500->write = ab8500_i2c_write;
ab8500->write_masked = ab8500_i2c_write_masked;
platform_set_drvdata(plf, ab8500);
ret = ab8500_init(ab8500, platid->driver_data);
if (ret)
kfree(ab8500);
return ret;
}
static int __devexit ab8500_i2c_remove(struct platform_device *plf)
{
struct ab8500 *ab8500 = platform_get_drvdata(plf);
ab8500_exit(ab8500);
kfree(ab8500);
return 0;
}
static const struct platform_device_id ab8500_id[] = {
{ "ab8500-i2c", AB8500_VERSION_AB8500 },
{ "ab8505-i2c", AB8500_VERSION_AB8505 },
{ "ab9540-i2c", AB8500_VERSION_AB9540 },
{ "ab8540-i2c", AB8500_VERSION_AB8540 },
{ }
};
static struct platform_driver ab8500_i2c_driver = {
.driver = {
.name = "ab8500-i2c",
.owner = THIS_MODULE,
},
.probe = ab8500_i2c_probe,
.remove = __devexit_p(ab8500_i2c_remove),
.id_table = ab8500_id,
};
static int __init ab8500_i2c_init(void)
{
return platform_driver_register(&ab8500_i2c_driver);
}
static void __exit ab8500_i2c_exit(void)
{
platform_driver_unregister(&ab8500_i2c_driver);
}
arch_initcall(ab8500_i2c_init);
module_exit(ab8500_i2c_exit);
MODULE_AUTHOR("Mattias WALLIN <mattias.wallin@stericsson.com");
MODULE_DESCRIPTION("AB8500 Core access via PRCMU I2C");
MODULE_LICENSE("GPL v2");
......@@ -61,10 +61,16 @@ static int __devexit ab8500_sysctrl_remove(struct platform_device *pdev)
return 0;
}
static const struct of_device_id ab8500_sysctrl_match[] = {
{ .compatible = "stericsson,ab8500-sysctrl", },
{}
};
static struct platform_driver ab8500_sysctrl_driver = {
.driver = {
.name = "ab8500-sysctrl",
.owner = THIS_MODULE,
.of_match_table = ab8500_sysctrl_match,
},
.probe = ab8500_sysctrl_probe,
.remove = __devexit_p(ab8500_sysctrl_remove),
......
......@@ -41,39 +41,26 @@
#include <linux/of_address.h>
#include <linux/mfd/anatop.h>
u32 anatop_get_bits(struct anatop *adata, u32 addr, int bit_shift,
int bit_width)
u32 anatop_read_reg(struct anatop *adata, u32 addr)
{
u32 val, mask;
if (bit_width == 32)
mask = ~0;
else
mask = (1 << bit_width) - 1;
val = readl(adata->ioreg + addr);
val = (val >> bit_shift) & mask;
return val;
return readl(adata->ioreg + addr);
}
EXPORT_SYMBOL_GPL(anatop_get_bits);
EXPORT_SYMBOL_GPL(anatop_read_reg);
void anatop_set_bits(struct anatop *adata, u32 addr, int bit_shift,
int bit_width, u32 data)
void anatop_write_reg(struct anatop *adata, u32 addr, u32 data, u32 mask)
{
u32 val, mask;
u32 val;
if (bit_width == 32)
mask = ~0;
else
mask = (1 << bit_width) - 1;
data &= mask;
spin_lock(&adata->reglock);
val = readl(adata->ioreg + addr) & ~(mask << bit_shift);
writel((data << bit_shift) | val, adata->ioreg + addr);
val = readl(adata->ioreg + addr);
val &= ~mask;
val |= data;
writel(val, adata->ioreg + addr);
spin_unlock(&adata->reglock);
}
EXPORT_SYMBOL_GPL(anatop_set_bits);
EXPORT_SYMBOL_GPL(anatop_write_reg);
static const struct of_device_id of_anatop_match[] = {
{ .compatible = "fsl,imx6q-anatop", },
......
......@@ -353,12 +353,28 @@ static int asic3_gpio_irq_type(struct irq_data *data, unsigned int type)
return 0;
}
static int asic3_gpio_irq_set_wake(struct irq_data *data, unsigned int on)
{
struct asic3 *asic = irq_data_get_irq_chip_data(data);
u32 bank, index;
u16 bit;
bank = asic3_irq_to_bank(asic, data->irq);
index = asic3_irq_to_index(asic, data->irq);
bit = 1<<index;
asic3_set_register(asic, bank + ASIC3_GPIO_SLEEP_MASK, bit, !on);
return 0;
}
static struct irq_chip asic3_gpio_irq_chip = {
.name = "ASIC3-GPIO",
.irq_ack = asic3_mask_gpio_irq,
.irq_mask = asic3_mask_gpio_irq,
.irq_unmask = asic3_unmask_gpio_irq,
.irq_set_type = asic3_gpio_irq_type,
.irq_set_wake = asic3_gpio_irq_set_wake,
};
static struct irq_chip asic3_irq_chip = {
......@@ -529,7 +545,7 @@ static int asic3_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
{
struct asic3 *asic = container_of(chip, struct asic3, gpio);
return (offset < ASIC3_NUM_GPIOS) ? asic->irq_base + offset : -ENXIO;
return asic->irq_base + offset;
}
static __init int asic3_gpio_probe(struct platform_device *pdev,
......@@ -894,10 +910,13 @@ static int __init asic3_mfd_probe(struct platform_device *pdev,
asic3_mmc_resources[0].start >>= asic->bus_shift;
asic3_mmc_resources[0].end >>= asic->bus_shift;
ret = mfd_add_devices(&pdev->dev, pdev->id,
if (pdata->clock_rate) {
ds1wm_pdata.clock_rate = pdata->clock_rate;
ret = mfd_add_devices(&pdev->dev, pdev->id,
&asic3_cell_ds1wm, 1, mem, asic->irq_base);
if (ret < 0)
goto out;
if (ret < 0)
goto out;
}
if (mem_sdio && (irq >= 0)) {
ret = mfd_add_devices(&pdev->dev, pdev->id,
......@@ -1000,6 +1019,9 @@ static int __init asic3_probe(struct platform_device *pdev)
asic3_mfd_probe(pdev, pdata, mem);
asic3_set_register(asic, ASIC3_OFFSET(EXTCF, SELECT),
(ASIC3_EXTCF_CF0_BUF_EN|ASIC3_EXTCF_CF0_PWAIT_EN), 1);
dev_info(asic->dev, "ASIC3 Core driver\n");
return 0;
......@@ -1021,6 +1043,9 @@ static int __devexit asic3_remove(struct platform_device *pdev)
int ret;
struct asic3 *asic = platform_get_drvdata(pdev);
asic3_set_register(asic, ASIC3_OFFSET(EXTCF, SELECT),
(ASIC3_EXTCF_CF0_BUF_EN|ASIC3_EXTCF_CF0_PWAIT_EN), 0);
asic3_mfd_remove(pdev);
ret = asic3_gpio_remove(pdev);
......
......@@ -186,18 +186,7 @@ static struct pci_driver cs5535_mfd_driver = {
.remove = __devexit_p(cs5535_mfd_remove),
};
static int __init cs5535_mfd_init(void)
{
return pci_register_driver(&cs5535_mfd_driver);
}
static void __exit cs5535_mfd_exit(void)
{
pci_unregister_driver(&cs5535_mfd_driver);
}
module_init(cs5535_mfd_init);
module_exit(cs5535_mfd_exit);
module_pci_driver(cs5535_mfd_driver);
MODULE_AUTHOR("Andres Salomon <dilinger@queued.net>");
MODULE_DESCRIPTION("MFD driver for CS5535/CS5536 southbridge's ISA PCI device");
......
......@@ -318,6 +318,135 @@ static bool da9052_reg_volatile(struct device *dev, unsigned int reg)
}
}
/*
* TBAT look-up table is computed from the R90 reg (8 bit register)
* reading as below. The battery temperature is in milliCentigrade
* TBAT = (1/(t1+1/298) - 273) * 1000 mC
* where t1 = (1/B)* ln(( ADCval * 2.5)/(R25*ITBAT*255))
* Default values are R25 = 10e3, B = 3380, ITBAT = 50e-6
* Example:
* R25=10E3, B=3380, ITBAT=50e-6, ADCVAL=62d calculates
* TBAT = 20015 mili degrees Centrigrade
*
*/
static const int32_t tbat_lookup[255] = {
183258, 144221, 124334, 111336, 101826, 94397, 88343, 83257,
78889, 75071, 71688, 68656, 65914, 63414, 61120, 59001,
570366, 55204, 53490, 51881, 50364, 48931, 47574, 46285,
45059, 43889, 42772, 41703, 40678, 39694, 38748, 37838,
36961, 36115, 35297, 34507, 33743, 33002, 32284, 31588,
30911, 30254, 29615, 28994, 28389, 27799, 27225, 26664,
26117, 25584, 25062, 24553, 24054, 23567, 23091, 22624,
22167, 21719, 21281, 20851, 20429, 20015, 19610, 19211,
18820, 18436, 18058, 17688, 17323, 16965, 16612, 16266,
15925, 15589, 15259, 14933, 14613, 14298, 13987, 13681,
13379, 13082, 12788, 12499, 12214, 11933, 11655, 11382,
11112, 10845, 10582, 10322, 10066, 9812, 9562, 9315,
9071, 8830, 8591, 8356, 8123, 7893, 7665, 7440,
7218, 6998, 6780, 6565, 6352, 6141, 5933, 5726,
5522, 5320, 5120, 4922, 4726, 4532, 4340, 4149,
3961, 3774, 3589, 3406, 3225, 3045, 2867, 2690,
2516, 2342, 2170, 2000, 1831, 1664, 1498, 1334,
1171, 1009, 849, 690, 532, 376, 221, 67,
-84, -236, -386, -535, -683, -830, -975, -1119,
-1263, -1405, -1546, -1686, -1825, -1964, -2101, -2237,
-2372, -2506, -2639, -2771, -2902, -3033, -3162, -3291,
-3418, -3545, -3671, -3796, -3920, -4044, -4166, -4288,
-4409, -4529, -4649, -4767, -4885, -5002, -5119, -5235,
-5349, -5464, -5577, -5690, -5802, -5913, -6024, -6134,
-6244, -6352, -6461, -6568, -6675, -6781, -6887, -6992,
-7096, -7200, -7303, -7406, -7508, -7609, -7710, -7810,
-7910, -8009, -8108, -8206, -8304, -8401, -8497, -8593,
-8689, -8784, -8878, -8972, -9066, -9159, -9251, -9343,
-9435, -9526, -9617, -9707, -9796, -9886, -9975, -10063,
-10151, -10238, -10325, -10412, -10839, -10923, -11007, -11090,
-11173, -11256, -11338, -11420, -11501, -11583, -11663, -11744,
-11823, -11903, -11982
};
static const u8 chan_mux[DA9052_ADC_VBBAT + 1] = {
[DA9052_ADC_VDDOUT] = DA9052_ADC_MAN_MUXSEL_VDDOUT,
[DA9052_ADC_ICH] = DA9052_ADC_MAN_MUXSEL_ICH,
[DA9052_ADC_TBAT] = DA9052_ADC_MAN_MUXSEL_TBAT,
[DA9052_ADC_VBAT] = DA9052_ADC_MAN_MUXSEL_VBAT,
[DA9052_ADC_IN4] = DA9052_ADC_MAN_MUXSEL_AD4,
[DA9052_ADC_IN5] = DA9052_ADC_MAN_MUXSEL_AD5,
[DA9052_ADC_IN6] = DA9052_ADC_MAN_MUXSEL_AD6,
[DA9052_ADC_VBBAT] = DA9052_ADC_MAN_MUXSEL_VBBAT
};
int da9052_adc_manual_read(struct da9052 *da9052, unsigned char channel)
{
int ret;
unsigned short calc_data;
unsigned short data;
unsigned char mux_sel;
if (channel > DA9052_ADC_VBBAT)
return -EINVAL;
mutex_lock(&da9052->auxadc_lock);
/* Channel gets activated on enabling the Conversion bit */
mux_sel = chan_mux[channel] | DA9052_ADC_MAN_MAN_CONV;
ret = da9052_reg_write(da9052, DA9052_ADC_MAN_REG, mux_sel);
if (ret < 0)
goto err;
/* Wait for an interrupt */
if (!wait_for_completion_timeout(&da9052->done,
msecs_to_jiffies(500))) {
dev_err(da9052->dev,
"timeout waiting for ADC conversion interrupt\n");
ret = -ETIMEDOUT;
goto err;
}
ret = da9052_reg_read(da9052, DA9052_ADC_RES_H_REG);
if (ret < 0)
goto err;
calc_data = (unsigned short)ret;
data = calc_data << 2;
ret = da9052_reg_read(da9052, DA9052_ADC_RES_L_REG);
if (ret < 0)
goto err;
calc_data = (unsigned short)(ret & DA9052_ADC_RES_LSB);
data |= calc_data;
ret = data;
err:
mutex_unlock(&da9052->auxadc_lock);
return ret;
}
EXPORT_SYMBOL_GPL(da9052_adc_manual_read);
static irqreturn_t da9052_auxadc_irq(int irq, void *irq_data)
{
struct da9052 *da9052 = irq_data;
complete(&da9052->done);
return IRQ_HANDLED;
}
int da9052_adc_read_temp(struct da9052 *da9052)
{
int tbat;
tbat = da9052_reg_read(da9052, DA9052_TBAT_RES_REG);
if (tbat <= 0)
return tbat;
/* ARRAY_SIZE check is not needed since TBAT is a 8-bit register */
return tbat_lookup[tbat - 1];
}
EXPORT_SYMBOL_GPL(da9052_adc_read_temp);
static struct resource da9052_rtc_resource = {
.name = "ALM",
.start = DA9052_IRQ_ALARM,
......@@ -646,6 +775,9 @@ int __devinit da9052_device_init(struct da9052 *da9052, u8 chip_id)
struct irq_desc *desc;
int ret;
mutex_init(&da9052->auxadc_lock);
init_completion(&da9052->done);
if (pdata && pdata->init != NULL)
pdata->init(da9052);
......@@ -665,6 +797,12 @@ int __devinit da9052_device_init(struct da9052 *da9052, u8 chip_id)
da9052->irq_base = regmap_irq_chip_get_base(da9052->irq_data);
ret = request_threaded_irq(DA9052_IRQ_ADC_EOM, NULL, da9052_auxadc_irq,
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
"adc irq", da9052);
if (ret != 0)
dev_err(da9052->dev, "DA9052 ADC IRQ failed ret=%d\n", ret);
ret = mfd_add_devices(da9052->dev, -1, da9052_subdev_info,
ARRAY_SIZE(da9052_subdev_info), NULL, 0);
if (ret)
......@@ -673,6 +811,7 @@ int __devinit da9052_device_init(struct da9052 *da9052, u8 chip_id)
return 0;
err:
free_irq(DA9052_IRQ_ADC_EOM, da9052);
mfd_remove_devices(da9052->dev);
regmap_err:
return ret;
......@@ -680,6 +819,7 @@ int __devinit da9052_device_init(struct da9052 *da9052, u8 chip_id)
void da9052_device_exit(struct da9052 *da9052)
{
free_irq(DA9052_IRQ_ADC_EOM, da9052);
regmap_del_irq_chip(da9052->chip_irq, da9052->irq_data);
mfd_remove_devices(da9052->dev);
}
......
......@@ -22,6 +22,11 @@
#include <linux/mfd/da9052/da9052.h>
#include <linux/mfd/da9052/reg.h>
#ifdef CONFIG_OF
#include <linux/of.h>
#include <linux/of_device.h>
#endif
static int da9052_i2c_enable_multiwrite(struct da9052 *da9052)
{
int reg_val, ret;
......@@ -41,13 +46,31 @@ static int da9052_i2c_enable_multiwrite(struct da9052 *da9052)
return 0;
}
static struct i2c_device_id da9052_i2c_id[] = {
{"da9052", DA9052},
{"da9053-aa", DA9053_AA},
{"da9053-ba", DA9053_BA},
{"da9053-bb", DA9053_BB},
{}
};
#ifdef CONFIG_OF
static const struct of_device_id dialog_dt_ids[] = {
{ .compatible = "dlg,da9052", .data = &da9052_i2c_id[0] },
{ .compatible = "dlg,da9053-aa", .data = &da9052_i2c_id[1] },
{ .compatible = "dlg,da9053-ab", .data = &da9052_i2c_id[2] },
{ .compatible = "dlg,da9053-bb", .data = &da9052_i2c_id[3] },
{ /* sentinel */ }
};
#endif
static int __devinit da9052_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct da9052 *da9052;
int ret;
da9052 = kzalloc(sizeof(struct da9052), GFP_KERNEL);
da9052 = devm_kzalloc(&client->dev, sizeof(struct da9052), GFP_KERNEL);
if (!da9052)
return -ENOMEM;
......@@ -55,8 +78,7 @@ static int __devinit da9052_i2c_probe(struct i2c_client *client,
I2C_FUNC_SMBUS_BYTE_DATA)) {
dev_info(&client->dev, "Error in %s:i2c_check_functionality\n",
__func__);
ret = -ENODEV;
goto err;
return -ENODEV;
}
da9052->dev = &client->dev;
......@@ -64,29 +86,39 @@ static int __devinit da9052_i2c_probe(struct i2c_client *client,
i2c_set_clientdata(client, da9052);
da9052->regmap = regmap_init_i2c(client, &da9052_regmap_config);
da9052->regmap = devm_regmap_init_i2c(client, &da9052_regmap_config);
if (IS_ERR(da9052->regmap)) {
ret = PTR_ERR(da9052->regmap);
dev_err(&client->dev, "Failed to allocate register map: %d\n",
ret);
goto err;
return ret;
}
ret = da9052_i2c_enable_multiwrite(da9052);
if (ret < 0)
goto err_regmap;
return ret;
#ifdef CONFIG_OF
if (!id) {
struct device_node *np = client->dev.of_node;
const struct of_device_id *deviceid;
deviceid = of_match_node(dialog_dt_ids, np);
id = (const struct i2c_device_id *)deviceid->data;
}
#endif
if (!id) {
ret = -ENODEV;
dev_err(&client->dev, "id is null.\n");
return ret;
}
ret = da9052_device_init(da9052, id->driver_data);
if (ret != 0)
goto err_regmap;
return ret;
return 0;
err_regmap:
regmap_exit(da9052->regmap);
err:
kfree(da9052);
return ret;
}
static int __devexit da9052_i2c_remove(struct i2c_client *client)
......@@ -94,20 +126,9 @@ static int __devexit da9052_i2c_remove(struct i2c_client *client)
struct da9052 *da9052 = i2c_get_clientdata(client);
da9052_device_exit(da9052);
regmap_exit(da9052->regmap);
kfree(da9052);
return 0;
}
static struct i2c_device_id da9052_i2c_id[] = {
{"da9052", DA9052},
{"da9053-aa", DA9053_AA},
{"da9053-ba", DA9053_BA},
{"da9053-bb", DA9053_BB},
{}
};
static struct i2c_driver da9052_i2c_driver = {
.probe = da9052_i2c_probe,
.remove = __devexit_p(da9052_i2c_remove),
......@@ -115,6 +136,9 @@ static struct i2c_driver da9052_i2c_driver = {
.driver = {
.name = "da9052",
.owner = THIS_MODULE,
#ifdef CONFIG_OF
.of_match_table = dialog_dt_ids,
#endif
},
};
......
......@@ -25,8 +25,9 @@ static int __devinit da9052_spi_probe(struct spi_device *spi)
{
int ret;
const struct spi_device_id *id = spi_get_device_id(spi);
struct da9052 *da9052 = kzalloc(sizeof(struct da9052), GFP_KERNEL);
struct da9052 *da9052;
da9052 = devm_kzalloc(&spi->dev, sizeof(struct da9052), GFP_KERNEL);
if (!da9052)
return -ENOMEM;
......@@ -42,25 +43,19 @@ static int __devinit da9052_spi_probe(struct spi_device *spi)
da9052_regmap_config.read_flag_mask = 1;
da9052_regmap_config.write_flag_mask = 0;
da9052->regmap = regmap_init_spi(spi, &da9052_regmap_config);
da9052->regmap = devm_regmap_init_spi(spi, &da9052_regmap_config);
if (IS_ERR(da9052->regmap)) {
ret = PTR_ERR(da9052->regmap);
dev_err(&spi->dev, "Failed to allocate register map: %d\n",
ret);
goto err;
return ret;
}
ret = da9052_device_init(da9052, id->driver_data);
if (ret != 0)
goto err_regmap;
return ret;
return 0;
err_regmap:
regmap_exit(da9052->regmap);
err:
kfree(da9052);
return ret;
}
static int __devexit da9052_spi_remove(struct spi_device *spi)
......@@ -68,9 +63,6 @@ static int __devexit da9052_spi_remove(struct spi_device *spi)
struct da9052 *da9052 = dev_get_drvdata(&spi->dev);
da9052_device_exit(da9052);
regmap_exit(da9052->regmap);
kfree(da9052);
return 0;
}
......@@ -88,7 +80,6 @@ static struct spi_driver da9052_spi_driver = {
.id_table = da9052_spi_id,
.driver = {
.name = "da9052",
.bus = &spi_bus_type,
.owner = THIS_MODULE,
},
};
......
......@@ -2720,6 +2720,7 @@ static struct regulator_consumer_supply db8500_vape_consumers[] = {
REGULATOR_SUPPLY("v-i2c", "nmk-i2c.1"),
REGULATOR_SUPPLY("v-i2c", "nmk-i2c.2"),
REGULATOR_SUPPLY("v-i2c", "nmk-i2c.3"),
REGULATOR_SUPPLY("v-i2c", "nmk-i2c.4"),
/* "v-mmc" changed to "vcore" in the mainline kernel */
REGULATOR_SUPPLY("vcore", "sdi0"),
REGULATOR_SUPPLY("vcore", "sdi1"),
......@@ -2958,9 +2959,10 @@ static struct mfd_cell db8500_prcmu_devs[] = {
* prcmu_fw_init - arch init call for the Linux PRCMU fw init logic
*
*/
static int __init db8500_prcmu_probe(struct platform_device *pdev)
static int __devinit db8500_prcmu_probe(struct platform_device *pdev)
{
int err = 0;
struct device_node *np = pdev->dev.of_node;
int irq = 0, err = 0;
if (ux500_is_svp())
return -ENODEV;
......@@ -2970,8 +2972,14 @@ static int __init db8500_prcmu_probe(struct platform_device *pdev)
/* Clean up the mailbox interrupts after pre-kernel code. */
writel(ALL_MBOX_BITS, PRCM_ARM_IT1_CLR);
err = request_threaded_irq(IRQ_DB8500_PRCMU1, prcmu_irq_handler,
prcmu_irq_thread_fn, IRQF_NO_SUSPEND, "prcmu", NULL);
if (np)
irq = platform_get_irq(pdev, 0);
if (!np || irq <= 0)
irq = IRQ_DB8500_PRCMU1;
err = request_threaded_irq(irq, prcmu_irq_handler,
prcmu_irq_thread_fn, IRQF_NO_SUSPEND, "prcmu", NULL);
if (err < 0) {
pr_err("prcmu: Failed to allocate IRQ_DB8500_PRCMU1.\n");
err = -EBUSY;
......@@ -2981,14 +2989,16 @@ static int __init db8500_prcmu_probe(struct platform_device *pdev)
if (cpu_is_u8500v20_or_later())
prcmu_config_esram0_deep_sleep(ESRAM0_DEEP_SLEEP_STATE_RET);
err = mfd_add_devices(&pdev->dev, 0, db8500_prcmu_devs,
ARRAY_SIZE(db8500_prcmu_devs), NULL,
0);
if (!np) {
err = mfd_add_devices(&pdev->dev, 0, db8500_prcmu_devs,
ARRAY_SIZE(db8500_prcmu_devs), NULL, 0);
if (err) {
pr_err("prcmu: Failed to add subdevices\n");
return err;
}
}
if (err)
pr_err("prcmu: Failed to add subdevices\n");
else
pr_info("DB8500 PRCMU initialized\n");
pr_info("DB8500 PRCMU initialized\n");
no_irq_return:
return err;
......@@ -2999,11 +3009,12 @@ static struct platform_driver db8500_prcmu_driver = {
.name = "db8500-prcmu",
.owner = THIS_MODULE,
},
.probe = db8500_prcmu_probe,
};
static int __init db8500_prcmu_init(void)
{
return platform_driver_probe(&db8500_prcmu_driver, db8500_prcmu_probe);
return platform_driver_register(&db8500_prcmu_driver);
}
arch_initcall(db8500_prcmu_init);
......
......@@ -406,7 +406,7 @@ static int __devinit intel_msic_probe(struct platform_device *pdev)
return -ENXIO;
}
msic = kzalloc(sizeof(*msic), GFP_KERNEL);
msic = devm_kzalloc(&pdev->dev, sizeof(*msic), GFP_KERNEL);
if (!msic)
return -ENOMEM;
......@@ -421,21 +421,13 @@ static int __devinit intel_msic_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "failed to get SRAM iomem resource\n");
ret = -ENODEV;
goto fail_free_msic;
return -ENODEV;
}
res = request_mem_region(res->start, resource_size(res), pdev->name);
if (!res) {
ret = -EBUSY;
goto fail_free_msic;
}
msic->irq_base = ioremap_nocache(res->start, resource_size(res));
msic->irq_base = devm_request_and_ioremap(&pdev->dev, res);
if (!msic->irq_base) {
dev_err(&pdev->dev, "failed to map SRAM memory\n");
ret = -ENOMEM;
goto fail_release_region;
return -ENOMEM;
}
platform_set_drvdata(pdev, msic);
......@@ -443,7 +435,7 @@ static int __devinit intel_msic_probe(struct platform_device *pdev)
ret = intel_msic_init_devices(msic);
if (ret) {
dev_err(&pdev->dev, "failed to initialize MSIC devices\n");
goto fail_unmap_mem;
return ret;
}
dev_info(&pdev->dev, "Intel MSIC version %c%d (vendor %#x)\n",
......@@ -451,27 +443,14 @@ static int __devinit intel_msic_probe(struct platform_device *pdev)
msic->vendor);
return 0;
fail_unmap_mem:
iounmap(msic->irq_base);
fail_release_region:
release_mem_region(res->start, resource_size(res));
fail_free_msic:
kfree(msic);
return ret;
}
static int __devexit intel_msic_remove(struct platform_device *pdev)
{
struct intel_msic *msic = platform_get_drvdata(pdev);
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
intel_msic_remove_devices(msic);
platform_set_drvdata(pdev, NULL);
iounmap(msic->irq_base);
release_mem_region(res->start, resource_size(res));
kfree(msic);
return 0;
}
......
......@@ -283,23 +283,8 @@ static struct pci_driver cmodio_pci_driver = {
.remove = __devexit_p(cmodio_pci_remove),
};
/*
* Module Init / Exit
*/
static int __init cmodio_init(void)
{
return pci_register_driver(&cmodio_pci_driver);
}
static void __exit cmodio_exit(void)
{
pci_unregister_driver(&cmodio_pci_driver);
}
module_pci_driver(cmodio_pci_driver);
MODULE_AUTHOR("Ira W. Snyder <iws@ovro.caltech.edu>");
MODULE_DESCRIPTION("Janz CMOD-IO PCI MODULbus Carrier Board Driver");
MODULE_LICENSE("GPL");
module_init(cmodio_init);
module_exit(cmodio_exit);
/*
* lm3533-core.c -- LM3533 Core
*
* Copyright (C) 2011-2012 Texas Instruments
*
* Author: Johan Hovold <jhovold@gmail.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/mfd/core.h>
#include <linux/regmap.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/mfd/lm3533.h>
#define LM3533_BOOST_OVP_MASK 0x06
#define LM3533_BOOST_OVP_SHIFT 1
#define LM3533_BOOST_FREQ_MASK 0x01
#define LM3533_BOOST_FREQ_SHIFT 0
#define LM3533_BL_ID_MASK 1
#define LM3533_LED_ID_MASK 3
#define LM3533_BL_ID_MAX 1
#define LM3533_LED_ID_MAX 3
#define LM3533_HVLED_ID_MAX 2
#define LM3533_LVLED_ID_MAX 5
#define LM3533_REG_OUTPUT_CONF1 0x10
#define LM3533_REG_OUTPUT_CONF2 0x11
#define LM3533_REG_BOOST_PWM 0x2c
#define LM3533_REG_MAX 0xb2
static struct mfd_cell lm3533_als_devs[] = {
{
.name = "lm3533-als",
.id = -1,
},
};
static struct mfd_cell lm3533_bl_devs[] = {
{
.name = "lm3533-backlight",
.id = 0,
},
{
.name = "lm3533-backlight",
.id = 1,
},
};
static struct mfd_cell lm3533_led_devs[] = {
{
.name = "lm3533-leds",
.id = 0,
},
{
.name = "lm3533-leds",
.id = 1,
},
{
.name = "lm3533-leds",
.id = 2,
},
{
.name = "lm3533-leds",
.id = 3,
},
};
int lm3533_read(struct lm3533 *lm3533, u8 reg, u8 *val)
{
int tmp;
int ret;
ret = regmap_read(lm3533->regmap, reg, &tmp);
if (ret < 0) {
dev_err(lm3533->dev, "failed to read register %02x: %d\n",
reg, ret);
return ret;
}
*val = tmp;
dev_dbg(lm3533->dev, "read [%02x]: %02x\n", reg, *val);
return ret;
}
EXPORT_SYMBOL_GPL(lm3533_read);
int lm3533_write(struct lm3533 *lm3533, u8 reg, u8 val)
{
int ret;
dev_dbg(lm3533->dev, "write [%02x]: %02x\n", reg, val);
ret = regmap_write(lm3533->regmap, reg, val);
if (ret < 0) {
dev_err(lm3533->dev, "failed to write register %02x: %d\n",
reg, ret);
}
return ret;
}
EXPORT_SYMBOL_GPL(lm3533_write);
int lm3533_update(struct lm3533 *lm3533, u8 reg, u8 val, u8 mask)
{
int ret;
dev_dbg(lm3533->dev, "update [%02x]: %02x/%02x\n", reg, val, mask);
ret = regmap_update_bits(lm3533->regmap, reg, mask, val);
if (ret < 0) {
dev_err(lm3533->dev, "failed to update register %02x: %d\n",
reg, ret);
}
return ret;
}
EXPORT_SYMBOL_GPL(lm3533_update);
static int lm3533_set_boost_freq(struct lm3533 *lm3533,
enum lm3533_boost_freq freq)
{
int ret;
ret = lm3533_update(lm3533, LM3533_REG_BOOST_PWM,
freq << LM3533_BOOST_FREQ_SHIFT,
LM3533_BOOST_FREQ_MASK);
if (ret)
dev_err(lm3533->dev, "failed to set boost frequency\n");
return ret;
}
static int lm3533_set_boost_ovp(struct lm3533 *lm3533,
enum lm3533_boost_ovp ovp)
{
int ret;
ret = lm3533_update(lm3533, LM3533_REG_BOOST_PWM,
ovp << LM3533_BOOST_OVP_SHIFT,
LM3533_BOOST_OVP_MASK);
if (ret)
dev_err(lm3533->dev, "failed to set boost ovp\n");
return ret;
}
/*
* HVLED output config -- output hvled controlled by backlight bl
*/
static int lm3533_set_hvled_config(struct lm3533 *lm3533, u8 hvled, u8 bl)
{
u8 val;
u8 mask;
int shift;
int ret;
if (hvled == 0 || hvled > LM3533_HVLED_ID_MAX)
return -EINVAL;
if (bl > LM3533_BL_ID_MAX)
return -EINVAL;
shift = hvled - 1;
mask = LM3533_BL_ID_MASK << shift;
val = bl << shift;
ret = lm3533_update(lm3533, LM3533_REG_OUTPUT_CONF1, val, mask);
if (ret)
dev_err(lm3533->dev, "failed to set hvled config\n");
return ret;
}
/*
* LVLED output config -- output lvled controlled by LED led
*/
static int lm3533_set_lvled_config(struct lm3533 *lm3533, u8 lvled, u8 led)
{
u8 reg;
u8 val;
u8 mask;
int shift;
int ret;
if (lvled == 0 || lvled > LM3533_LVLED_ID_MAX)
return -EINVAL;
if (led > LM3533_LED_ID_MAX)
return -EINVAL;
if (lvled < 4) {
reg = LM3533_REG_OUTPUT_CONF1;
shift = 2 * lvled;
} else {
reg = LM3533_REG_OUTPUT_CONF2;
shift = 2 * (lvled - 4);
}
mask = LM3533_LED_ID_MASK << shift;
val = led << shift;
ret = lm3533_update(lm3533, reg, val, mask);
if (ret)
dev_err(lm3533->dev, "failed to set lvled config\n");
return ret;
}
static void lm3533_enable(struct lm3533 *lm3533)
{
if (gpio_is_valid(lm3533->gpio_hwen))
gpio_set_value(lm3533->gpio_hwen, 1);
}
static void lm3533_disable(struct lm3533 *lm3533)
{
if (gpio_is_valid(lm3533->gpio_hwen))
gpio_set_value(lm3533->gpio_hwen, 0);
}
enum lm3533_attribute_type {
LM3533_ATTR_TYPE_BACKLIGHT,
LM3533_ATTR_TYPE_LED,
};
struct lm3533_device_attribute {
struct device_attribute dev_attr;
enum lm3533_attribute_type type;
union {
struct {
u8 id;
} output;
} u;
};
#define to_lm3533_dev_attr(_attr) \
container_of(_attr, struct lm3533_device_attribute, dev_attr)
static ssize_t show_output(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct lm3533 *lm3533 = dev_get_drvdata(dev);
struct lm3533_device_attribute *lattr = to_lm3533_dev_attr(attr);
int id = lattr->u.output.id;
u8 reg;
u8 val;
u8 mask;
int shift;
int ret;
if (lattr->type == LM3533_ATTR_TYPE_BACKLIGHT) {
reg = LM3533_REG_OUTPUT_CONF1;
shift = id - 1;
mask = LM3533_BL_ID_MASK << shift;
} else {
if (id < 4) {
reg = LM3533_REG_OUTPUT_CONF1;
shift = 2 * id;
} else {
reg = LM3533_REG_OUTPUT_CONF2;
shift = 2 * (id - 4);
}
mask = LM3533_LED_ID_MASK << shift;
}
ret = lm3533_read(lm3533, reg, &val);
if (ret)
return ret;
val = (val & mask) >> shift;
return scnprintf(buf, PAGE_SIZE, "%u\n", val);
}
static ssize_t store_output(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
struct lm3533 *lm3533 = dev_get_drvdata(dev);
struct lm3533_device_attribute *lattr = to_lm3533_dev_attr(attr);
int id = lattr->u.output.id;
u8 val;
int ret;
if (kstrtou8(buf, 0, &val))
return -EINVAL;
if (lattr->type == LM3533_ATTR_TYPE_BACKLIGHT)
ret = lm3533_set_hvled_config(lm3533, id, val);
else
ret = lm3533_set_lvled_config(lm3533, id, val);
if (ret)
return ret;
return len;
}
#define LM3533_OUTPUT_ATTR(_name, _mode, _show, _store, _type, _id) \
struct lm3533_device_attribute lm3533_dev_attr_##_name = \
{ .dev_attr = __ATTR(_name, _mode, _show, _store), \
.type = _type, \
.u.output = { .id = _id }, }
#define LM3533_OUTPUT_ATTR_RW(_name, _type, _id) \
LM3533_OUTPUT_ATTR(output_##_name, S_IRUGO | S_IWUSR, \
show_output, store_output, _type, _id)
#define LM3533_OUTPUT_HVLED_ATTR_RW(_nr) \
LM3533_OUTPUT_ATTR_RW(hvled##_nr, LM3533_ATTR_TYPE_BACKLIGHT, _nr)
#define LM3533_OUTPUT_LVLED_ATTR_RW(_nr) \
LM3533_OUTPUT_ATTR_RW(lvled##_nr, LM3533_ATTR_TYPE_LED, _nr)
/*
* Output config:
*
* output_hvled<nr> 0-1
* output_lvled<nr> 0-3
*/
static LM3533_OUTPUT_HVLED_ATTR_RW(1);
static LM3533_OUTPUT_HVLED_ATTR_RW(2);
static LM3533_OUTPUT_LVLED_ATTR_RW(1);
static LM3533_OUTPUT_LVLED_ATTR_RW(2);
static LM3533_OUTPUT_LVLED_ATTR_RW(3);
static LM3533_OUTPUT_LVLED_ATTR_RW(4);
static LM3533_OUTPUT_LVLED_ATTR_RW(5);
static struct attribute *lm3533_attributes[] = {
&lm3533_dev_attr_output_hvled1.dev_attr.attr,
&lm3533_dev_attr_output_hvled2.dev_attr.attr,
&lm3533_dev_attr_output_lvled1.dev_attr.attr,
&lm3533_dev_attr_output_lvled2.dev_attr.attr,
&lm3533_dev_attr_output_lvled3.dev_attr.attr,
&lm3533_dev_attr_output_lvled4.dev_attr.attr,
&lm3533_dev_attr_output_lvled5.dev_attr.attr,
NULL,
};
#define to_dev_attr(_attr) \
container_of(_attr, struct device_attribute, attr)
static umode_t lm3533_attr_is_visible(struct kobject *kobj,
struct attribute *attr, int n)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct lm3533 *lm3533 = dev_get_drvdata(dev);
struct device_attribute *dattr = to_dev_attr(attr);
struct lm3533_device_attribute *lattr = to_lm3533_dev_attr(dattr);
enum lm3533_attribute_type type = lattr->type;
umode_t mode = attr->mode;
if (!lm3533->have_backlights && type == LM3533_ATTR_TYPE_BACKLIGHT)
mode = 0;
else if (!lm3533->have_leds && type == LM3533_ATTR_TYPE_LED)
mode = 0;
return mode;
};
static struct attribute_group lm3533_attribute_group = {
.is_visible = lm3533_attr_is_visible,
.attrs = lm3533_attributes
};
static int __devinit lm3533_device_als_init(struct lm3533 *lm3533)
{
struct lm3533_platform_data *pdata = lm3533->dev->platform_data;
int ret;
if (!pdata->als)
return 0;
lm3533_als_devs[0].platform_data = pdata->als;
lm3533_als_devs[0].pdata_size = sizeof(*pdata->als);
ret = mfd_add_devices(lm3533->dev, 0, lm3533_als_devs, 1, NULL, 0);
if (ret) {
dev_err(lm3533->dev, "failed to add ALS device\n");
return ret;
}
lm3533->have_als = 1;
return 0;
}
static int __devinit lm3533_device_bl_init(struct lm3533 *lm3533)
{
struct lm3533_platform_data *pdata = lm3533->dev->platform_data;
int i;
int ret;
if (!pdata->backlights || pdata->num_backlights == 0)
return 0;
if (pdata->num_backlights > ARRAY_SIZE(lm3533_bl_devs))
pdata->num_backlights = ARRAY_SIZE(lm3533_bl_devs);
for (i = 0; i < pdata->num_backlights; ++i) {
lm3533_bl_devs[i].platform_data = &pdata->backlights[i];
lm3533_bl_devs[i].pdata_size = sizeof(pdata->backlights[i]);
}
ret = mfd_add_devices(lm3533->dev, 0, lm3533_bl_devs,
pdata->num_backlights, NULL, 0);
if (ret) {
dev_err(lm3533->dev, "failed to add backlight devices\n");
return ret;
}
lm3533->have_backlights = 1;
return 0;
}
static int __devinit lm3533_device_led_init(struct lm3533 *lm3533)
{
struct lm3533_platform_data *pdata = lm3533->dev->platform_data;
int i;
int ret;
if (!pdata->leds || pdata->num_leds == 0)
return 0;
if (pdata->num_leds > ARRAY_SIZE(lm3533_led_devs))
pdata->num_leds = ARRAY_SIZE(lm3533_led_devs);
for (i = 0; i < pdata->num_leds; ++i) {
lm3533_led_devs[i].platform_data = &pdata->leds[i];
lm3533_led_devs[i].pdata_size = sizeof(pdata->leds[i]);
}
ret = mfd_add_devices(lm3533->dev, 0, lm3533_led_devs,
pdata->num_leds, NULL, 0);
if (ret) {
dev_err(lm3533->dev, "failed to add LED devices\n");
return ret;
}
lm3533->have_leds = 1;
return 0;
}
static int __devinit lm3533_device_setup(struct lm3533 *lm3533,
struct lm3533_platform_data *pdata)
{
int ret;
ret = lm3533_set_boost_freq(lm3533, pdata->boost_freq);
if (ret)
return ret;
ret = lm3533_set_boost_ovp(lm3533, pdata->boost_ovp);
if (ret)
return ret;
return 0;
}
static int __devinit lm3533_device_init(struct lm3533 *lm3533)
{
struct lm3533_platform_data *pdata = lm3533->dev->platform_data;
int ret;
dev_dbg(lm3533->dev, "%s\n", __func__);
if (!pdata) {
dev_err(lm3533->dev, "no platform data\n");
return -EINVAL;
}
lm3533->gpio_hwen = pdata->gpio_hwen;
dev_set_drvdata(lm3533->dev, lm3533);
if (gpio_is_valid(lm3533->gpio_hwen)) {
ret = gpio_request_one(lm3533->gpio_hwen, GPIOF_OUT_INIT_LOW,
"lm3533-hwen");
if (ret < 0) {
dev_err(lm3533->dev,
"failed to request HWEN GPIO %d\n",
lm3533->gpio_hwen);
return ret;
}
}
lm3533_enable(lm3533);
ret = lm3533_device_setup(lm3533, pdata);
if (ret)
goto err_disable;
lm3533_device_als_init(lm3533);
lm3533_device_bl_init(lm3533);
lm3533_device_led_init(lm3533);
ret = sysfs_create_group(&lm3533->dev->kobj, &lm3533_attribute_group);
if (ret < 0) {
dev_err(lm3533->dev, "failed to create sysfs attributes\n");
goto err_unregister;
}
return 0;
err_unregister:
mfd_remove_devices(lm3533->dev);
err_disable:
lm3533_disable(lm3533);
if (gpio_is_valid(lm3533->gpio_hwen))
gpio_free(lm3533->gpio_hwen);
return ret;
}
static void __devexit lm3533_device_exit(struct lm3533 *lm3533)
{
dev_dbg(lm3533->dev, "%s\n", __func__);
sysfs_remove_group(&lm3533->dev->kobj, &lm3533_attribute_group);
mfd_remove_devices(lm3533->dev);
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)
{
switch (reg) {
case 0x10 ... 0x2c:
case 0x30 ... 0x38:
case 0x40 ... 0x45:
case 0x50 ... 0x57:
case 0x60 ... 0x6e:
case 0x70 ... 0x75:
case 0x80 ... 0x85:
case 0x90 ... 0x95:
case 0xa0 ... 0xa5:
case 0xb0 ... 0xb2:
return true;
default:
return false;
}
}
static bool lm3533_volatile_register(struct device *dev, unsigned int reg)
{
switch (reg) {
case 0x34 ... 0x36: /* zone */
case 0x37 ... 0x38: /* adc */
case 0xb0 ... 0xb1: /* fault */
return true;
default:
return false;
}
}
static bool lm3533_precious_register(struct device *dev, unsigned int reg)
{
switch (reg) {
case 0x34: /* zone */
return true;
default:
return false;
}
}
static struct regmap_config regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = LM3533_REG_MAX,
.readable_reg = lm3533_readable_register,
.volatile_reg = lm3533_volatile_register,
.precious_reg = lm3533_precious_register,
};
static int __devinit lm3533_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct lm3533 *lm3533;
int ret;
dev_dbg(&i2c->dev, "%s\n", __func__);
lm3533 = devm_kzalloc(&i2c->dev, sizeof(*lm3533), GFP_KERNEL);
if (!lm3533)
return -ENOMEM;
i2c_set_clientdata(i2c, lm3533);
lm3533->regmap = devm_regmap_init_i2c(i2c, &regmap_config);
if (IS_ERR(lm3533->regmap))
return PTR_ERR(lm3533->regmap);
lm3533->dev = &i2c->dev;
lm3533->irq = i2c->irq;
ret = lm3533_device_init(lm3533);
if (ret)
return ret;
return 0;
}
static int __devexit lm3533_i2c_remove(struct i2c_client *i2c)
{
struct lm3533 *lm3533 = i2c_get_clientdata(i2c);
dev_dbg(&i2c->dev, "%s\n", __func__);
lm3533_device_exit(lm3533);
return 0;
}
static const struct i2c_device_id lm3533_i2c_ids[] = {
{ "lm3533", 0 },
{ },
};
MODULE_DEVICE_TABLE(i2c, lm3533_i2c_ids);
static struct i2c_driver lm3533_i2c_driver = {
.driver = {
.name = "lm3533",
.owner = THIS_MODULE,
},
.id_table = lm3533_i2c_ids,
.probe = lm3533_i2c_probe,
.remove = __devexit_p(lm3533_i2c_remove),
};
static int __init lm3533_i2c_init(void)
{
return i2c_add_driver(&lm3533_i2c_driver);
}
subsys_initcall(lm3533_i2c_init);
static void __exit lm3533_i2c_exit(void)
{
i2c_del_driver(&lm3533_i2c_driver);
}
module_exit(lm3533_i2c_exit);
MODULE_AUTHOR("Johan Hovold <jhovold@gmail.com>");
MODULE_DESCRIPTION("LM3533 Core");
MODULE_LICENSE("GPL");
/*
* lm3533-ctrlbank.c -- LM3533 Generic Control Bank interface
*
* Copyright (C) 2011-2012 Texas Instruments
*
* Author: Johan Hovold <jhovold@gmail.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <linux/device.h>
#include <linux/module.h>
#include <linux/mfd/lm3533.h>
#define LM3533_MAX_CURRENT_MIN 5000
#define LM3533_MAX_CURRENT_MAX 29800
#define LM3533_MAX_CURRENT_STEP 800
#define LM3533_BRIGHTNESS_MAX 255
#define LM3533_PWM_MAX 0x3f
#define LM3533_REG_PWM_BASE 0x14
#define LM3533_REG_MAX_CURRENT_BASE 0x1f
#define LM3533_REG_CTRLBANK_ENABLE 0x27
#define LM3533_REG_BRIGHTNESS_BASE 0x40
static inline u8 lm3533_ctrlbank_get_reg(struct lm3533_ctrlbank *cb, u8 base)
{
return base + cb->id;
}
int lm3533_ctrlbank_enable(struct lm3533_ctrlbank *cb)
{
u8 mask;
int ret;
dev_dbg(cb->dev, "%s - %d\n", __func__, cb->id);
mask = 1 << cb->id;
ret = lm3533_update(cb->lm3533, LM3533_REG_CTRLBANK_ENABLE,
mask, mask);
if (ret)
dev_err(cb->dev, "failed to enable ctrlbank %d\n", cb->id);
return ret;
}
EXPORT_SYMBOL_GPL(lm3533_ctrlbank_enable);
int lm3533_ctrlbank_disable(struct lm3533_ctrlbank *cb)
{
u8 mask;
int ret;
dev_dbg(cb->dev, "%s - %d\n", __func__, cb->id);
mask = 1 << cb->id;
ret = lm3533_update(cb->lm3533, LM3533_REG_CTRLBANK_ENABLE, 0, mask);
if (ret)
dev_err(cb->dev, "failed to disable ctrlbank %d\n", cb->id);
return ret;
}
EXPORT_SYMBOL_GPL(lm3533_ctrlbank_disable);
/*
* Full-scale current.
*
* imax 5000 - 29800 uA (800 uA step)
*/
int lm3533_ctrlbank_set_max_current(struct lm3533_ctrlbank *cb, u16 imax)
{
u8 reg;
u8 val;
int ret;
if (imax < LM3533_MAX_CURRENT_MIN || imax > LM3533_MAX_CURRENT_MAX)
return -EINVAL;
val = (imax - LM3533_MAX_CURRENT_MIN) / LM3533_MAX_CURRENT_STEP;
reg = lm3533_ctrlbank_get_reg(cb, LM3533_REG_MAX_CURRENT_BASE);
ret = lm3533_write(cb->lm3533, reg, val);
if (ret)
dev_err(cb->dev, "failed to set max current\n");
return ret;
}
EXPORT_SYMBOL_GPL(lm3533_ctrlbank_set_max_current);
#define lm3533_ctrlbank_set(_name, _NAME) \
int lm3533_ctrlbank_set_##_name(struct lm3533_ctrlbank *cb, u8 val) \
{ \
u8 reg; \
int ret; \
\
if (val > LM3533_##_NAME##_MAX) \
return -EINVAL; \
\
reg = lm3533_ctrlbank_get_reg(cb, LM3533_REG_##_NAME##_BASE); \
ret = lm3533_write(cb->lm3533, reg, val); \
if (ret) \
dev_err(cb->dev, "failed to set " #_name "\n"); \
\
return ret; \
} \
EXPORT_SYMBOL_GPL(lm3533_ctrlbank_set_##_name);
#define lm3533_ctrlbank_get(_name, _NAME) \
int lm3533_ctrlbank_get_##_name(struct lm3533_ctrlbank *cb, u8 *val) \
{ \
u8 reg; \
int ret; \
\
reg = lm3533_ctrlbank_get_reg(cb, LM3533_REG_##_NAME##_BASE); \
ret = lm3533_read(cb->lm3533, reg, val); \
if (ret) \
dev_err(cb->dev, "failed to get " #_name "\n"); \
\
return ret; \
} \
EXPORT_SYMBOL_GPL(lm3533_ctrlbank_get_##_name);
lm3533_ctrlbank_set(brightness, BRIGHTNESS);
lm3533_ctrlbank_get(brightness, BRIGHTNESS);
/*
* PWM-input control mask:
*
* bit 5 - PWM-input enabled in Zone 4
* bit 4 - PWM-input enabled in Zone 3
* bit 3 - PWM-input enabled in Zone 2
* bit 2 - PWM-input enabled in Zone 1
* bit 1 - PWM-input enabled in Zone 0
* bit 0 - PWM-input enabled
*/
lm3533_ctrlbank_set(pwm, PWM);
lm3533_ctrlbank_get(pwm, PWM);
MODULE_AUTHOR("Johan Hovold <jhovold@gmail.com>");
MODULE_DESCRIPTION("LM3533 Control Bank interface");
MODULE_LICENSE("GPL");
此差异已折叠。
......@@ -36,6 +36,7 @@
#define GPIOBASE 0x44
#define GPIO_IO_SIZE 64
#define GPIO_IO_SIZE_CENTERTON 128
#define WDTBASE 0x84
#define WDT_IO_SIZE 64
......@@ -68,7 +69,7 @@ static struct resource wdt_sch_resource = {
static struct mfd_cell tunnelcreek_cells[] = {
{
.name = "tunnelcreek_wdt",
.name = "ie6xx_wdt",
.num_resources = 1,
.resources = &wdt_sch_resource,
},
......@@ -77,6 +78,7 @@ static struct mfd_cell tunnelcreek_cells[] = {
static DEFINE_PCI_DEVICE_TABLE(lpc_sch_ids) = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SCH_LPC) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ITC_LPC) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CENTERTON_ILB) },
{ 0, }
};
MODULE_DEVICE_TABLE(pci, lpc_sch_ids);
......@@ -115,7 +117,11 @@ static int __devinit lpc_sch_probe(struct pci_dev *dev,
}
gpio_sch_resource.start = base_addr;
gpio_sch_resource.end = base_addr + GPIO_IO_SIZE - 1;
if (id->device == PCI_DEVICE_ID_INTEL_CENTERTON_ILB)
gpio_sch_resource.end = base_addr + GPIO_IO_SIZE_CENTERTON - 1;
else
gpio_sch_resource.end = base_addr + GPIO_IO_SIZE - 1;
for (i=0; i < ARRAY_SIZE(lpc_sch_cells); i++)
lpc_sch_cells[i].id = id->device;
......@@ -125,7 +131,8 @@ static int __devinit lpc_sch_probe(struct pci_dev *dev,
if (ret)
goto out_dev;
if (id->device == PCI_DEVICE_ID_INTEL_ITC_LPC) {
if (id->device == PCI_DEVICE_ID_INTEL_ITC_LPC
|| id->device == PCI_DEVICE_ID_INTEL_CENTERTON_ILB) {
pci_read_config_dword(dev, WDTBASE, &base_addr_cfg);
if (!(base_addr_cfg & (1 << 31))) {
dev_err(&dev->dev, "Decode of the WDT I/O range disabled\n");
......@@ -167,18 +174,7 @@ static struct pci_driver lpc_sch_driver = {
.remove = __devexit_p(lpc_sch_remove),
};
static int __init lpc_sch_init(void)
{
return pci_register_driver(&lpc_sch_driver);
}
static void __exit lpc_sch_exit(void)
{
pci_unregister_driver(&lpc_sch_driver);
}
module_init(lpc_sch_init);
module_exit(lpc_sch_exit);
module_pci_driver(lpc_sch_driver);
MODULE_AUTHOR("Denis Turischev <denis@compulab.co.il>");
MODULE_DESCRIPTION("LPC interface for Intel Poulsbo SCH");
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
/*
* Copyright 2012 Creative Product Design
* Marc Reilly <marc@cpdesign.com.au>
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License version 2 as published by the
* Free Software Foundation.
*/
#ifndef __DRIVERS_MFD_MC13XXX_H
#define __DRIVERS_MFD_MC13XXX_H
#include <linux/mutex.h>
#include <linux/regmap.h>
#include <linux/mfd/mc13xxx.h>
enum mc13xxx_id {
MC13XXX_ID_MC13783,
MC13XXX_ID_MC13892,
MC13XXX_ID_INVALID,
};
#define MC13XXX_NUMREGS 0x3f
struct mc13xxx {
struct regmap *regmap;
struct device *dev;
enum mc13xxx_id ictype;
struct mutex lock;
int irq;
int flags;
irq_handler_t irqhandler[MC13XXX_NUM_IRQ];
void *irqdata[MC13XXX_NUM_IRQ];
int adcflags;
};
int mc13xxx_common_init(struct mc13xxx *mc13xxx,
struct mc13xxx_platform_data *pdata, int irq);
void mc13xxx_common_cleanup(struct mc13xxx *mc13xxx);
#endif /* __DRIVERS_MFD_MC13XXX_H */
此差异已折叠。
......@@ -75,6 +75,7 @@ static struct deepsleep_control_data deepsleep_data[] = {
(RC5T583_EXT_PWRREQ1_CONTROL | RC5T583_EXT_PWRREQ2_CONTROL)
static struct mfd_cell rc5t583_subdevs[] = {
{.name = "rc5t583-gpio",},
{.name = "rc5t583-regulator",},
{.name = "rc5t583-rtc", },
{.name = "rc5t583-key", }
......@@ -267,7 +268,7 @@ static int __devinit rc5t583_i2c_probe(struct i2c_client *i2c,
rc5t583->dev = &i2c->dev;
i2c_set_clientdata(i2c, rc5t583);
rc5t583->regmap = regmap_init_i2c(i2c, &rc5t583_regmap_config);
rc5t583->regmap = devm_regmap_init_i2c(i2c, &rc5t583_regmap_config);
if (IS_ERR(rc5t583->regmap)) {
ret = PTR_ERR(rc5t583->regmap);
dev_err(&i2c->dev, "regmap initialization failed: %d\n", ret);
......@@ -276,7 +277,7 @@ static int __devinit rc5t583_i2c_probe(struct i2c_client *i2c,
ret = rc5t583_clear_ext_power_req(rc5t583, pdata);
if (ret < 0)
goto err_irq_init;
return ret;
if (i2c->irq) {
ret = rc5t583_irq_init(rc5t583, i2c->irq, pdata->irq_base);
......@@ -299,8 +300,6 @@ static int __devinit rc5t583_i2c_probe(struct i2c_client *i2c,
err_add_devs:
if (irq_init_success)
rc5t583_irq_exit(rc5t583);
err_irq_init:
regmap_exit(rc5t583->regmap);
return ret;
}
......@@ -310,7 +309,6 @@ static int __devexit rc5t583_i2c_remove(struct i2c_client *i2c)
mfd_remove_devices(rc5t583->dev);
rc5t583_irq_exit(rc5t583);
regmap_exit(rc5t583->regmap);
return 0;
}
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册