Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/sameo/mfd-2.6

* 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/sameo/mfd-2.6: (59 commits)
  rtc: max8925: Add function to work as wakeup source
  mfd: Add pm ops to max8925
  mfd: Convert aat2870 to dev_pm_ops
  mfd: Still check other interrupts if we get a wm831x touchscreen IRQ
  mfd: Introduce missing kfree in 88pm860x probe routine
  mfd: Add S5M series configuration
  mfd: Add s5m series irq driver
  mfd: Add S5M core driver
  mfd: Improve mc13xxx dt binding document
  mfd: Fix stmpe section mismatch
  mfd: Fix stmpe build warning
  mfd: Fix STMPE I2c build failure
  mfd: Constify aat2870-core i2c_device_id table
  gpio: Add support for stmpe variant 801
  mfd: Add support for stmpe variant 801
  mfd: Add support for stmpe variant 610
  mfd: Add support for STMPE SPI interface
  mfd: Separate out STMPE controller and interface specific code
  misc: Remove max8997-muic sysfs attributes
  mfd: Remove unused wm831x_irq_data_to_mask_reg()
  ...

Fix up trivial conflict in drivers/leds/Kconfig due to addition of
LEDS_MAX8997 and LEDS_TCA6507 next to each other.
This commit is contained in:
Linus Torvalds 2012-01-13 20:43:32 -08:00
commit 21ebd6c68b
98 changed files with 3639 additions and 550 deletions

View file

@ -0,0 +1,78 @@
* Freescale MC13783/MC13892 Power Management Integrated Circuit (PMIC)
Required properties:
- compatible : Should be "fsl,mc13783" or "fsl,mc13892"
Optional properties:
- fsl,mc13xxx-uses-adc : Indicate the ADC is being used
- fsl,mc13xxx-uses-codec : Indicate the Audio Codec is being used
- fsl,mc13xxx-uses-rtc : Indicate the RTC is being used
- fsl,mc13xxx-uses-touch : Indicate the touchscreen controller is being used
Sub-nodes:
- regulators : Contain the regulator nodes. The MC13892 regulators are
bound using their names as listed below with their registers and bits
for enabling.
vcoincell : regulator VCOINCELL (register 13, bit 23)
sw1 : regulator SW1 (register 24, bit 0)
sw2 : regulator SW2 (register 25, bit 0)
sw3 : regulator SW3 (register 26, bit 0)
sw4 : regulator SW4 (register 27, bit 0)
swbst : regulator SWBST (register 29, bit 20)
vgen1 : regulator VGEN1 (register 32, bit 0)
viohi : regulator VIOHI (register 32, bit 3)
vdig : regulator VDIG (register 32, bit 9)
vgen2 : regulator VGEN2 (register 32, bit 12)
vpll : regulator VPLL (register 32, bit 15)
vusb2 : regulator VUSB2 (register 32, bit 18)
vgen3 : regulator VGEN3 (register 33, bit 0)
vcam : regulator VCAM (register 33, bit 6)
vvideo : regulator VVIDEO (register 33, bit 12)
vaudio : regulator VAUDIO (register 33, bit 15)
vsd : regulator VSD (register 33, bit 18)
gpo1 : regulator GPO1 (register 34, bit 6)
gpo2 : regulator GPO2 (register 34, bit 8)
gpo3 : regulator GPO3 (register 34, bit 10)
gpo4 : regulator GPO4 (register 34, bit 12)
pwgt1spi : regulator PWGT1SPI (register 34, bit 15)
pwgt2spi : regulator PWGT2SPI (register 34, bit 16)
vusb : regulator VUSB (register 50, bit 3)
The bindings details of individual regulator device can be found in:
Documentation/devicetree/bindings/regulator/regulator.txt
Examples:
ecspi@70010000 { /* ECSPI1 */
fsl,spi-num-chipselects = <2>;
cs-gpios = <&gpio3 24 0>, /* GPIO4_24 */
<&gpio3 25 0>; /* GPIO4_25 */
status = "okay";
pmic: mc13892@0 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "fsl,mc13892";
spi-max-frequency = <6000000>;
reg = <0>;
interrupt-parent = <&gpio0>;
interrupts = <8>;
regulators {
sw1_reg: mc13892__sw1 {
regulator-min-microvolt = <600000>;
regulator-max-microvolt = <1375000>;
regulator-boot-on;
regulator-always-on;
};
sw2_reg: mc13892__sw2 {
regulator-min-microvolt = <900000>;
regulator-max-microvolt = <1850000>;
regulator-boot-on;
regulator-always-on;
};
};
};
};

View file

@ -0,0 +1,47 @@
Texas Instruments TWL family
The TWLs are Integrated Power Management Chips.
Some version might contain much more analog function like
USB transceiver or Audio amplifier.
These chips are connected to an i2c bus.
Required properties:
- compatible : Must be "ti,twl4030";
For Integrated power-management/audio CODEC device used in OMAP3
based boards
- compatible : Must be "ti,twl6030";
For Integrated power-management used in OMAP4 based boards
- interrupts : This i2c device has an IRQ line connected to the main SoC
- interrupt-controller : Since the twl support several interrupts internally,
it is considered as an interrupt controller cascaded to the SoC one.
- #interrupt-cells = <1>;
- interrupt-parent : The parent interrupt controller.
Optional node:
- Child nodes contain in the twl. The twl family is made of several variants
that support a different number of features.
The children nodes will thus depend of the capability of the variant.
Example:
/*
* Integrated Power Management Chip
* http://www.ti.com/lit/ds/symlink/twl6030.pdf
*/
twl@48 {
compatible = "ti,twl6030";
reg = <0x48>;
interrupts = <39>; /* IRQ_SYS_1N cascaded to gic */
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&gic>;
#address-cells = <1>;
#size-cells = <0>;
twl_rtc {
compatible = "ti,twl_rtc";
interrupts = <11>;
reg = <0>;
};
};

View file

@ -202,6 +202,7 @@ static struct irda_platform_data assabet_irda_data = {
static struct mcp_plat_data assabet_mcp_data = {
.mccr0 = MCCR0_ADM,
.sclk_rate = 11981000,
.codec = "ucb1x00",
};
static void __init assabet_init(void)
@ -252,6 +253,17 @@ static void __init assabet_init(void)
sa11x0_register_mtd(&assabet_flash_data, assabet_flash_resources,
ARRAY_SIZE(assabet_flash_resources));
sa11x0_register_irda(&assabet_irda_data);
/*
* Setup the PPC unit correctly.
*/
PPDR &= ~PPC_RXD4;
PPDR |= PPC_TXD4 | PPC_SCLK | PPC_SFRM;
PSDR |= PPC_RXD4;
PSDR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
PPSR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
ASSABET_BCR_set(ASSABET_BCR_CODEC_RST);
sa11x0_register_mcp(&assabet_mcp_data);
}

View file

@ -124,12 +124,23 @@ static void __init cerf_map_io(void)
static struct mcp_plat_data cerf_mcp_data = {
.mccr0 = MCCR0_ADM,
.sclk_rate = 11981000,
.codec = "ucb1x00",
};
static void __init cerf_init(void)
{
platform_add_devices(cerf_devices, ARRAY_SIZE(cerf_devices));
sa11x0_register_mtd(&cerf_flash_data, &cerf_flash_resource, 1);
/*
* Setup the PPC unit correctly.
*/
PPDR &= ~PPC_RXD4;
PPDR |= PPC_TXD4 | PPC_SCLK | PPC_SFRM;
PSDR |= PPC_RXD4;
PSDR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
PPSR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
sa11x0_register_mcp(&cerf_mcp_data);
}

View file

@ -27,6 +27,7 @@
#include <linux/timer.h>
#include <linux/gpio.h>
#include <linux/pda_power.h>
#include <linux/mfd/ucb1x00.h>
#include <mach/hardware.h>
#include <asm/mach-types.h>
@ -85,10 +86,15 @@ static struct scoop_pcmcia_config collie_pcmcia_config = {
.num_devs = 1,
};
static struct ucb1x00_plat_data collie_ucb1x00_data = {
.gpio_base = COLLIE_TC35143_GPIO_BASE,
};
static struct mcp_plat_data collie_mcp_data = {
.mccr0 = MCCR0_ADM | MCCR0_ExtClk,
.sclk_rate = 9216000,
.gpio_base = COLLIE_TC35143_GPIO_BASE,
.codec = "ucb1x00",
.codec_pdata = &collie_ucb1x00_data,
};
/*
@ -351,6 +357,16 @@ static void __init collie_init(void)
sa11x0_register_mtd(&collie_flash_data, collie_flash_resources,
ARRAY_SIZE(collie_flash_resources));
/*
* Setup the PPC unit correctly.
*/
PPDR &= ~PPC_RXD4;
PPDR |= PPC_TXD4 | PPC_SCLK | PPC_SFRM;
PSDR |= PPC_RXD4;
PSDR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
PPSR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
sa11x0_register_mcp(&collie_mcp_data);
sharpsl_save_param();

View file

@ -217,10 +217,15 @@ static struct platform_device sa11x0uart3_device = {
static struct resource sa11x0mcp_resources[] = {
[0] = {
.start = __PREG(Ser4MCCR0),
.end = __PREG(Ser4MCCR0) + 0xffff,
.end = __PREG(Ser4MCCR0) + 0x1C - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = __PREG(Ser4MCCR1),
.end = __PREG(Ser4MCCR1) + 0x4 - 1,
.flags = IORESOURCE_MEM,
},
[2] = {
.start = IRQ_Ser4MCP,
.end = IRQ_Ser4MCP,
.flags = IORESOURCE_IRQ,

View file

@ -17,6 +17,8 @@ struct mcp_plat_data {
u32 mccr1;
unsigned int sclk_rate;
int gpio_base;
const char *codec;
void *codec_pdata;
};
#endif

View file

@ -24,10 +24,20 @@
static struct mcp_plat_data lart_mcp_data = {
.mccr0 = MCCR0_ADM,
.sclk_rate = 11981000,
.codec = "ucb1x00",
};
static void __init lart_init(void)
{
/*
* Setup the PPC unit correctly.
*/
PPDR &= ~PPC_RXD4;
PPDR |= PPC_TXD4 | PPC_SCLK | PPC_SFRM;
PSDR |= PPC_RXD4;
PSDR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
PPSR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
sa11x0_register_mcp(&lart_mcp_data);
}

View file

@ -55,11 +55,22 @@ static struct resource shannon_flash_resource = {
static struct mcp_plat_data shannon_mcp_data = {
.mccr0 = MCCR0_ADM,
.sclk_rate = 11981000,
.codec = "ucb1x00",
};
static void __init shannon_init(void)
{
sa11x0_register_mtd(&shannon_flash_data, &shannon_flash_resource, 1);
/*
* Setup the PPC unit correctly.
*/
PPDR &= ~PPC_RXD4;
PPDR |= PPC_TXD4 | PPC_SCLK | PPC_SFRM;
PSDR |= PPC_RXD4;
PSDR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
PPSR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
sa11x0_register_mcp(&shannon_mcp_data);
}

View file

@ -14,6 +14,7 @@
#include <linux/mtd/partitions.h>
#include <linux/io.h>
#include <linux/gpio.h>
#include <linux/mfd/ucb1x00.h>
#include <asm/irq.h>
#include <mach/hardware.h>
@ -187,10 +188,15 @@ static struct resource simpad_flash_resources [] = {
}
};
static struct ucb1x00_plat_data simpad_ucb1x00_data = {
.gpio_base = SIMPAD_UCB1X00_GPIO_BASE,
};
static struct mcp_plat_data simpad_mcp_data = {
.mccr0 = MCCR0_ADM,
.sclk_rate = 11981000,
.gpio_base = SIMPAD_UCB1X00_GPIO_BASE,
.codec = "ucb1300",
.codec_pdata = &simpad_ucb1x00_data,
};
@ -378,6 +384,16 @@ static int __init simpad_init(void)
sa11x0_register_mtd(&simpad_flash_data, simpad_flash_resources,
ARRAY_SIZE(simpad_flash_resources));
/*
* Setup the PPC unit correctly.
*/
PPDR &= ~PPC_RXD4;
PPDR |= PPC_TXD4 | PPC_SCLK | PPC_SFRM;
PSDR |= PPC_RXD4;
PSDR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
PPSR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
sa11x0_register_mcp(&simpad_mcp_data);
ret = platform_add_devices(devices, ARRAY_SIZE(devices));

View file

@ -19,11 +19,11 @@
#include <linux/amba/pl022.h>
#include <linux/amba/serial.h>
#include <linux/spi/spi.h>
#include <linux/mfd/ab8500.h>
#include <linux/mfd/abx500/ab8500.h>
#include <linux/regulator/ab8500.h>
#include <linux/mfd/tc3589x.h>
#include <linux/mfd/tps6105x.h>
#include <linux/mfd/ab8500/gpio.h>
#include <linux/mfd/abx500/ab8500-gpio.h>
#include <linux/leds-lp5521.h>
#include <linux/input.h>
#include <linux/smsc911x.h>

View file

@ -10,7 +10,7 @@
#include <linux/amba/bus.h>
#include <linux/irq.h>
#include <linux/i2c.h>
#include <linux/mfd/ab5500/ab5500.h>
#include <linux/mfd/abx500/ab5500.h>
#include <asm/hardware/gic.h>
#include <asm/mach/arch.h>

View file

@ -9,7 +9,7 @@
#define __MACH_IRQS_BOARD_MOP500_H
/* Number of AB8500 irqs is taken from header file */
#include <linux/mfd/ab8500.h>
#include <linux/mfd/abx500/ab8500.h>
#define MOP500_AB8500_IRQ_BASE IRQ_BOARD_START
#define MOP500_AB8500_IRQ_END (MOP500_AB8500_IRQ_BASE \

View file

@ -65,7 +65,14 @@ static void stmpe_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
u8 reg = stmpe->regs[which] - (offset / 8);
u8 mask = 1 << (offset % 8);
stmpe_reg_write(stmpe, reg, mask);
/*
* Some variants have single register for gpio set/clear functionality.
* For them we need to write 0 to clear and 1 to set.
*/
if (stmpe->regs[STMPE_IDX_GPSR_LSB] == stmpe->regs[STMPE_IDX_GPCR_LSB])
stmpe_set_bits(stmpe, reg, mask, val ? mask : 0);
else
stmpe_reg_write(stmpe, reg, mask);
}
static int stmpe_gpio_direction_output(struct gpio_chip *chip,
@ -132,6 +139,10 @@ static int stmpe_gpio_irq_set_type(struct irq_data *d, unsigned int type)
if (type == IRQ_TYPE_LEVEL_LOW || type == IRQ_TYPE_LEVEL_HIGH)
return -EINVAL;
/* STMPE801 doesn't have RE and FE registers */
if (stmpe_gpio->stmpe->partnum == STMPE801)
return 0;
if (type == IRQ_TYPE_EDGE_RISING)
stmpe_gpio->regs[REG_RE][regoffset] |= mask;
else
@ -165,6 +176,11 @@ static void stmpe_gpio_irq_sync_unlock(struct irq_data *d)
int i, j;
for (i = 0; i < CACHE_NR_REGS; i++) {
/* STMPE801 doesn't have RE and FE registers */
if ((stmpe->partnum == STMPE801) &&
(i != REG_IE))
continue;
for (j = 0; j < num_banks; j++) {
u8 old = stmpe_gpio->oldregs[i][j];
u8 new = stmpe_gpio->regs[i][j];
@ -241,8 +257,11 @@ static irqreturn_t stmpe_gpio_irq(int irq, void *dev)
}
stmpe_reg_write(stmpe, statmsbreg + i, status[i]);
stmpe_reg_write(stmpe, stmpe->regs[STMPE_IDX_GPEDR_MSB] + i,
status[i]);
/* Edge detect register is not present on 801 */
if (stmpe->partnum != STMPE801)
stmpe_reg_write(stmpe, stmpe->regs[STMPE_IDX_GPEDR_MSB]
+ i, status[i]);
}
return IRQ_HANDLED;

View file

@ -12,7 +12,7 @@
#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/mfd/ab8500.h>
#include <linux/mfd/abx500/ab8500.h>
#include <linux/slab.h>
/**

View file

@ -396,6 +396,13 @@ config LEDS_TCA6507
LED driver chips accessed via the I2C bus.
Driver support brightness control and hardware-assisted blinking.
config LEDS_MAX8997
tristate "LED support for MAX8997 PMIC"
depends on LEDS_CLASS && MFD_MAX8997
help
This option enables support for on-chip LED drivers on
MAXIM MAX8997 PMIC.
config LEDS_TRIGGERS
bool "LED Trigger support"
depends on LEDS_CLASS

View file

@ -44,6 +44,7 @@ obj-$(CONFIG_LEDS_NS2) += leds-ns2.o
obj-$(CONFIG_LEDS_NETXBIG) += leds-netxbig.o
obj-$(CONFIG_LEDS_ASIC3) += leds-asic3.o
obj-$(CONFIG_LEDS_RENESAS_TPU) += leds-renesas-tpu.o
obj-$(CONFIG_LEDS_MAX8997) += leds-max8997.o
# LED SPI Drivers
obj-$(CONFIG_LEDS_DAC124S085) += leds-dac124s085.o

372
drivers/leds/leds-max8997.c Normal file
View file

@ -0,0 +1,372 @@
/*
* leds-max8997.c - LED class driver for MAX8997 LEDs.
*
* Copyright (C) 2011 Samsung Electronics
* Donggeun Kim <dg77.kim@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#include <linux/module.h>
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
#include <linux/leds.h>
#include <linux/mfd/max8997.h>
#include <linux/mfd/max8997-private.h>
#include <linux/platform_device.h>
#define MAX8997_LED_FLASH_SHIFT 3
#define MAX8997_LED_FLASH_CUR_MASK 0xf8
#define MAX8997_LED_MOVIE_SHIFT 4
#define MAX8997_LED_MOVIE_CUR_MASK 0xf0
#define MAX8997_LED_FLASH_MAX_BRIGHTNESS 0x1f
#define MAX8997_LED_MOVIE_MAX_BRIGHTNESS 0xf
#define MAX8997_LED_NONE_MAX_BRIGHTNESS 0
#define MAX8997_LED0_FLASH_MASK 0x1
#define MAX8997_LED0_FLASH_PIN_MASK 0x5
#define MAX8997_LED0_MOVIE_MASK 0x8
#define MAX8997_LED0_MOVIE_PIN_MASK 0x28
#define MAX8997_LED1_FLASH_MASK 0x2
#define MAX8997_LED1_FLASH_PIN_MASK 0x6
#define MAX8997_LED1_MOVIE_MASK 0x10
#define MAX8997_LED1_MOVIE_PIN_MASK 0x30
#define MAX8997_LED_BOOST_ENABLE_MASK (1 << 6)
struct max8997_led {
struct max8997_dev *iodev;
struct led_classdev cdev;
bool enabled;
int id;
enum max8997_led_mode led_mode;
struct mutex mutex;
};
static void max8997_led_clear_mode(struct max8997_led *led,
enum max8997_led_mode mode)
{
struct i2c_client *client = led->iodev->i2c;
u8 val = 0, mask = 0;
int ret;
switch (mode) {
case MAX8997_FLASH_MODE:
mask = led->id ?
MAX8997_LED1_FLASH_MASK : MAX8997_LED0_FLASH_MASK;
break;
case MAX8997_MOVIE_MODE:
mask = led->id ?
MAX8997_LED1_MOVIE_MASK : MAX8997_LED0_MOVIE_MASK;
break;
case MAX8997_FLASH_PIN_CONTROL_MODE:
mask = led->id ?
MAX8997_LED1_FLASH_PIN_MASK : MAX8997_LED0_FLASH_PIN_MASK;
break;
case MAX8997_MOVIE_PIN_CONTROL_MODE:
mask = led->id ?
MAX8997_LED1_MOVIE_PIN_MASK : MAX8997_LED0_MOVIE_PIN_MASK;
break;
default:
break;
}
if (mask) {
ret = max8997_update_reg(client,
MAX8997_REG_LEN_CNTL, val, mask);
if (ret)
dev_err(led->iodev->dev,
"failed to update register(%d)\n", ret);
}
}
static void max8997_led_set_mode(struct max8997_led *led,
enum max8997_led_mode mode)
{
int ret;
struct i2c_client *client = led->iodev->i2c;
u8 mask = 0;
/* First, clear the previous mode */
max8997_led_clear_mode(led, led->led_mode);
switch (mode) {
case MAX8997_FLASH_MODE:
mask = led->id ?
MAX8997_LED1_FLASH_MASK : MAX8997_LED0_FLASH_MASK;
led->cdev.max_brightness = MAX8997_LED_FLASH_MAX_BRIGHTNESS;
break;
case MAX8997_MOVIE_MODE:
mask = led->id ?
MAX8997_LED1_MOVIE_MASK : MAX8997_LED0_MOVIE_MASK;
led->cdev.max_brightness = MAX8997_LED_MOVIE_MAX_BRIGHTNESS;
break;
case MAX8997_FLASH_PIN_CONTROL_MODE:
mask = led->id ?
MAX8997_LED1_FLASH_PIN_MASK : MAX8997_LED0_FLASH_PIN_MASK;
led->cdev.max_brightness = MAX8997_LED_FLASH_MAX_BRIGHTNESS;
break;
case MAX8997_MOVIE_PIN_CONTROL_MODE:
mask = led->id ?
MAX8997_LED1_MOVIE_PIN_MASK : MAX8997_LED0_MOVIE_PIN_MASK;
led->cdev.max_brightness = MAX8997_LED_MOVIE_MAX_BRIGHTNESS;
break;
default:
led->cdev.max_brightness = MAX8997_LED_NONE_MAX_BRIGHTNESS;
break;
}
if (mask) {
ret = max8997_update_reg(client,
MAX8997_REG_LEN_CNTL, mask, mask);
if (ret)
dev_err(led->iodev->dev,
"failed to update register(%d)\n", ret);
}
led->led_mode = mode;
}
static void max8997_led_enable(struct max8997_led *led, bool enable)
{
int ret;
struct i2c_client *client = led->iodev->i2c;
u8 val = 0, mask = MAX8997_LED_BOOST_ENABLE_MASK;
if (led->enabled == enable)
return;
val = enable ? MAX8997_LED_BOOST_ENABLE_MASK : 0;
ret = max8997_update_reg(client, MAX8997_REG_BOOST_CNTL, val, mask);
if (ret)
dev_err(led->iodev->dev,
"failed to update register(%d)\n", ret);
led->enabled = enable;
}
static void max8997_led_set_current(struct max8997_led *led,
enum led_brightness value)
{
int ret;
struct i2c_client *client = led->iodev->i2c;
u8 val = 0, mask = 0, reg = 0;
switch (led->led_mode) {
case MAX8997_FLASH_MODE:
case MAX8997_FLASH_PIN_CONTROL_MODE:
val = value << MAX8997_LED_FLASH_SHIFT;
mask = MAX8997_LED_FLASH_CUR_MASK;
reg = led->id ? MAX8997_REG_FLASH2_CUR : MAX8997_REG_FLASH1_CUR;
break;
case MAX8997_MOVIE_MODE:
case MAX8997_MOVIE_PIN_CONTROL_MODE:
val = value << MAX8997_LED_MOVIE_SHIFT;
mask = MAX8997_LED_MOVIE_CUR_MASK;
reg = MAX8997_REG_MOVIE_CUR;
break;
default:
break;
}
if (mask) {
ret = max8997_update_reg(client, reg, val, mask);
if (ret)
dev_err(led->iodev->dev,
"failed to update register(%d)\n", ret);
}
}
static void max8997_led_brightness_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
struct max8997_led *led =
container_of(led_cdev, struct max8997_led, cdev);
if (value) {
max8997_led_set_current(led, value);
max8997_led_enable(led, true);
} else {
max8997_led_set_current(led, value);
max8997_led_enable(led, false);
}
}
static ssize_t max8997_led_show_mode(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
struct max8997_led *led =
container_of(led_cdev, struct max8997_led, cdev);
ssize_t ret = 0;
mutex_lock(&led->mutex);
switch (led->led_mode) {
case MAX8997_FLASH_MODE:
ret += sprintf(buf, "FLASH\n");
break;
case MAX8997_MOVIE_MODE:
ret += sprintf(buf, "MOVIE\n");
break;
case MAX8997_FLASH_PIN_CONTROL_MODE:
ret += sprintf(buf, "FLASH_PIN_CONTROL\n");
break;
case MAX8997_MOVIE_PIN_CONTROL_MODE:
ret += sprintf(buf, "MOVIE_PIN_CONTROL\n");
break;
default:
ret += sprintf(buf, "NONE\n");
break;
}
mutex_unlock(&led->mutex);
return ret;
}
static ssize_t max8997_led_store_mode(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
struct max8997_led *led =
container_of(led_cdev, struct max8997_led, cdev);
enum max8997_led_mode mode;
mutex_lock(&led->mutex);
if (!strncmp(buf, "FLASH_PIN_CONTROL", 17))
mode = MAX8997_FLASH_PIN_CONTROL_MODE;
else if (!strncmp(buf, "MOVIE_PIN_CONTROL", 17))
mode = MAX8997_MOVIE_PIN_CONTROL_MODE;
else if (!strncmp(buf, "FLASH", 5))
mode = MAX8997_FLASH_MODE;
else if (!strncmp(buf, "MOVIE", 5))
mode = MAX8997_MOVIE_MODE;
else
mode = MAX8997_NONE;
max8997_led_set_mode(led, mode);
mutex_unlock(&led->mutex);
return size;
}
static DEVICE_ATTR(mode, 0644, max8997_led_show_mode, max8997_led_store_mode);
static int __devinit max8997_led_probe(struct platform_device *pdev)
{
struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent);
struct max8997_platform_data *pdata = dev_get_platdata(iodev->dev);
struct max8997_led *led;
char name[20];
int ret = 0;
if (pdata == NULL) {
dev_err(&pdev->dev, "no platform data\n");
return -ENODEV;
}
led = kzalloc(sizeof(*led), GFP_KERNEL);
if (led == NULL) {
ret = -ENOMEM;
goto err_mem;
}
led->id = pdev->id;
snprintf(name, sizeof(name), "max8997-led%d", pdev->id);
led->cdev.name = name;
led->cdev.brightness_set = max8997_led_brightness_set;
led->cdev.flags |= LED_CORE_SUSPENDRESUME;
led->cdev.brightness = 0;
led->iodev = iodev;
/* initialize mode and brightness according to platform_data */
if (pdata->led_pdata) {
u8 mode = 0, brightness = 0;
mode = pdata->led_pdata->mode[led->id];
brightness = pdata->led_pdata->brightness[led->id];
max8997_led_set_mode(led, pdata->led_pdata->mode[led->id]);
if (brightness > led->cdev.max_brightness)
brightness = led->cdev.max_brightness;
max8997_led_set_current(led, brightness);
led->cdev.brightness = brightness;
} else {
max8997_led_set_mode(led, MAX8997_NONE);
max8997_led_set_current(led, 0);
}
mutex_init(&led->mutex);
platform_set_drvdata(pdev, led);
ret = led_classdev_register(&pdev->dev, &led->cdev);
if (ret < 0)
goto err_led;
ret = device_create_file(led->cdev.dev, &dev_attr_mode);
if (ret != 0) {
dev_err(&pdev->dev,
"failed to create file: %d\n", ret);
goto err_file;
}
return 0;
err_file:
led_classdev_unregister(&led->cdev);
err_led:
kfree(led);
err_mem:
return ret;
}
static int __devexit max8997_led_remove(struct platform_device *pdev)
{
struct max8997_led *led = platform_get_drvdata(pdev);
device_remove_file(led->cdev.dev, &dev_attr_mode);
led_classdev_unregister(&led->cdev);
kfree(led);
return 0;
}
static struct platform_driver max8997_led_driver = {
.driver = {
.name = "max8997-led",
.owner = THIS_MODULE,
},
.probe = max8997_led_probe,
.remove = __devexit_p(max8997_led_remove),
};
static int __init max8997_led_init(void)
{
return platform_driver_register(&max8997_led_driver);
}
module_init(max8997_led_init);
static void __exit max8997_led_exit(void)
{
platform_driver_unregister(&max8997_led_driver);
}
module_exit(max8997_led_exit);
MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>");
MODULE_DESCRIPTION("MAX8997 LED driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:max8997-led");

View file

@ -12,51 +12,20 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/i2c.h>
#include <linux/err.h>
#include <linux/regmap.h>
#include <linux/mfd/88pm860x.h>
#include <linux/slab.h>
static inline int pm860x_read_device(struct i2c_client *i2c,
int reg, int bytes, void *dest)
{
unsigned char data;
int ret;
data = (unsigned char)reg;
ret = i2c_master_send(i2c, &data, 1);
if (ret < 0)
return ret;
ret = i2c_master_recv(i2c, dest, bytes);
if (ret < 0)
return ret;
return 0;
}
static inline int pm860x_write_device(struct i2c_client *i2c,
int reg, int bytes, void *src)
{
unsigned char buf[bytes + 1];
int ret;
buf[0] = (unsigned char)reg;
memcpy(&buf[1], src, bytes);
ret = i2c_master_send(i2c, buf, bytes + 1);
if (ret < 0)
return ret;
return 0;
}
int pm860x_reg_read(struct i2c_client *i2c, int reg)
{
struct pm860x_chip *chip = i2c_get_clientdata(i2c);
unsigned char data;
struct regmap *map = (i2c == chip->client) ? chip->regmap
: chip->regmap_companion;
unsigned int data;
int ret;
mutex_lock(&chip->io_lock);
ret = pm860x_read_device(i2c, reg, 1, &data);
mutex_unlock(&chip->io_lock);
ret = regmap_read(map, reg, &data);
if (ret < 0)
return ret;
else
@ -68,12 +37,11 @@ int pm860x_reg_write(struct i2c_client *i2c, int reg,
unsigned char data)
{
struct pm860x_chip *chip = i2c_get_clientdata(i2c);
struct regmap *map = (i2c == chip->client) ? chip->regmap
: chip->regmap_companion;
int ret;
mutex_lock(&chip->io_lock);
ret = pm860x_write_device(i2c, reg, 1, &data);
mutex_unlock(&chip->io_lock);
ret = regmap_write(map, reg, data);
return ret;
}
EXPORT_SYMBOL(pm860x_reg_write);
@ -82,12 +50,11 @@ int pm860x_bulk_read(struct i2c_client *i2c, int reg,
int count, unsigned char *buf)
{
struct pm860x_chip *chip = i2c_get_clientdata(i2c);
struct regmap *map = (i2c == chip->client) ? chip->regmap
: chip->regmap_companion;
int ret;
mutex_lock(&chip->io_lock);
ret = pm860x_read_device(i2c, reg, count, buf);
mutex_unlock(&chip->io_lock);
ret = regmap_raw_read(map, reg, buf, count);
return ret;
}
EXPORT_SYMBOL(pm860x_bulk_read);
@ -96,12 +63,11 @@ int pm860x_bulk_write(struct i2c_client *i2c, int reg,
int count, unsigned char *buf)
{
struct pm860x_chip *chip = i2c_get_clientdata(i2c);
struct regmap *map = (i2c == chip->client) ? chip->regmap
: chip->regmap_companion;
int ret;
mutex_lock(&chip->io_lock);
ret = pm860x_write_device(i2c, reg, count, buf);
mutex_unlock(&chip->io_lock);
ret = regmap_raw_write(map, reg, buf, count);
return ret;
}
EXPORT_SYMBOL(pm860x_bulk_write);
@ -110,39 +76,78 @@ int pm860x_set_bits(struct i2c_client *i2c, int reg,
unsigned char mask, unsigned char data)
{
struct pm860x_chip *chip = i2c_get_clientdata(i2c);
unsigned char value;
struct regmap *map = (i2c == chip->client) ? chip->regmap
: chip->regmap_companion;
int ret;
mutex_lock(&chip->io_lock);
ret = pm860x_read_device(i2c, reg, 1, &value);
if (ret < 0)
goto out;
value &= ~mask;
value |= data;
ret = pm860x_write_device(i2c, reg, 1, &value);
out:
mutex_unlock(&chip->io_lock);
ret = regmap_update_bits(map, reg, mask, data);
return ret;
}
EXPORT_SYMBOL(pm860x_set_bits);
static int read_device(struct i2c_client *i2c, int reg,
int bytes, void *dest)
{
unsigned char msgbuf0[I2C_SMBUS_BLOCK_MAX + 3];
unsigned char msgbuf1[I2C_SMBUS_BLOCK_MAX + 2];
struct i2c_adapter *adap = i2c->adapter;
struct i2c_msg msg[2] = {{i2c->addr, 0, 1, msgbuf0},
{i2c->addr, I2C_M_RD, 0, msgbuf1},
};
int num = 1, ret = 0;
if (dest == NULL)
return -EINVAL;
msgbuf0[0] = (unsigned char)reg; /* command */
msg[1].len = bytes;
/* if data needs to read back, num should be 2 */
if (bytes > 0)
num = 2;
ret = adap->algo->master_xfer(adap, msg, num);
memcpy(dest, msgbuf1, bytes);
if (ret < 0)
return ret;
return 0;
}
static int write_device(struct i2c_client *i2c, int reg,
int bytes, void *src)
{
unsigned char buf[bytes + 1];
struct i2c_adapter *adap = i2c->adapter;
struct i2c_msg msg;
int ret;
buf[0] = (unsigned char)reg;
memcpy(&buf[1], src, bytes);
msg.addr = i2c->addr;
msg.flags = 0;
msg.len = bytes + 1;
msg.buf = buf;
ret = adap->algo->master_xfer(adap, &msg, 1);
if (ret < 0)
return ret;
return 0;
}
int pm860x_page_reg_read(struct i2c_client *i2c, int reg)
{
struct pm860x_chip *chip = i2c_get_clientdata(i2c);
unsigned char zero = 0;
unsigned char data;
int ret;
mutex_lock(&chip->io_lock);
pm860x_write_device(i2c, 0xFA, 0, &zero);
pm860x_write_device(i2c, 0xFB, 0, &zero);
pm860x_write_device(i2c, 0xFF, 0, &zero);
ret = pm860x_read_device(i2c, reg, 1, &data);
i2c_lock_adapter(i2c->adapter);
read_device(i2c, 0xFA, 0, &zero);
read_device(i2c, 0xFB, 0, &zero);
read_device(i2c, 0xFF, 0, &zero);
ret = read_device(i2c, reg, 1, &data);
if (ret >= 0)
ret = (int)data;
pm860x_write_device(i2c, 0xFE, 0, &zero);
pm860x_write_device(i2c, 0xFC, 0, &zero);
mutex_unlock(&chip->io_lock);
read_device(i2c, 0xFE, 0, &zero);
read_device(i2c, 0xFC, 0, &zero);
i2c_unlock_adapter(i2c->adapter);
return ret;
}
EXPORT_SYMBOL(pm860x_page_reg_read);
@ -150,18 +155,17 @@ EXPORT_SYMBOL(pm860x_page_reg_read);
int pm860x_page_reg_write(struct i2c_client *i2c, int reg,
unsigned char data)
{
struct pm860x_chip *chip = i2c_get_clientdata(i2c);
unsigned char zero;
int ret;
mutex_lock(&chip->io_lock);
pm860x_write_device(i2c, 0xFA, 0, &zero);
pm860x_write_device(i2c, 0xFB, 0, &zero);
pm860x_write_device(i2c, 0xFF, 0, &zero);
ret = pm860x_write_device(i2c, reg, 1, &data);
pm860x_write_device(i2c, 0xFE, 0, &zero);
pm860x_write_device(i2c, 0xFC, 0, &zero);
mutex_unlock(&chip->io_lock);
i2c_lock_adapter(i2c->adapter);
read_device(i2c, 0xFA, 0, &zero);
read_device(i2c, 0xFB, 0, &zero);
read_device(i2c, 0xFF, 0, &zero);
ret = write_device(i2c, reg, 1, &data);
read_device(i2c, 0xFE, 0, &zero);
read_device(i2c, 0xFC, 0, &zero);
i2c_unlock_adapter(i2c->adapter);
return ret;
}
EXPORT_SYMBOL(pm860x_page_reg_write);
@ -169,18 +173,17 @@ EXPORT_SYMBOL(pm860x_page_reg_write);
int pm860x_page_bulk_read(struct i2c_client *i2c, int reg,
int count, unsigned char *buf)
{
struct pm860x_chip *chip = i2c_get_clientdata(i2c);
unsigned char zero = 0;
int ret;
mutex_lock(&chip->io_lock);
pm860x_write_device(i2c, 0xFA, 0, &zero);
pm860x_write_device(i2c, 0xFB, 0, &zero);
pm860x_write_device(i2c, 0xFF, 0, &zero);
ret = pm860x_read_device(i2c, reg, count, buf);
pm860x_write_device(i2c, 0xFE, 0, &zero);
pm860x_write_device(i2c, 0xFC, 0, &zero);
mutex_unlock(&chip->io_lock);
i2c_lock_adapter(i2c->adapter);
read_device(i2c, 0xfa, 0, &zero);
read_device(i2c, 0xfb, 0, &zero);
read_device(i2c, 0xff, 0, &zero);
ret = read_device(i2c, reg, count, buf);
read_device(i2c, 0xFE, 0, &zero);
read_device(i2c, 0xFC, 0, &zero);
i2c_unlock_adapter(i2c->adapter);
return ret;
}
EXPORT_SYMBOL(pm860x_page_bulk_read);
@ -188,18 +191,18 @@ EXPORT_SYMBOL(pm860x_page_bulk_read);
int pm860x_page_bulk_write(struct i2c_client *i2c, int reg,
int count, unsigned char *buf)
{
struct pm860x_chip *chip = i2c_get_clientdata(i2c);
unsigned char zero = 0;
int ret;
mutex_lock(&chip->io_lock);
pm860x_write_device(i2c, 0xFA, 0, &zero);
pm860x_write_device(i2c, 0xFB, 0, &zero);
pm860x_write_device(i2c, 0xFF, 0, &zero);
ret = pm860x_write_device(i2c, reg, count, buf);
pm860x_write_device(i2c, 0xFE, 0, &zero);
pm860x_write_device(i2c, 0xFC, 0, &zero);
mutex_unlock(&chip->io_lock);
i2c_lock_adapter(i2c->adapter);
read_device(i2c, 0xFA, 0, &zero);
read_device(i2c, 0xFB, 0, &zero);
read_device(i2c, 0xFF, 0, &zero);
ret = write_device(i2c, reg, count, buf);
read_device(i2c, 0xFE, 0, &zero);
read_device(i2c, 0xFC, 0, &zero);
i2c_unlock_adapter(i2c->adapter);
i2c_unlock_adapter(i2c->adapter);
return ret;
}
EXPORT_SYMBOL(pm860x_page_bulk_write);
@ -207,25 +210,24 @@ EXPORT_SYMBOL(pm860x_page_bulk_write);
int pm860x_page_set_bits(struct i2c_client *i2c, int reg,
unsigned char mask, unsigned char data)
{
struct pm860x_chip *chip = i2c_get_clientdata(i2c);
unsigned char zero;
unsigned char value;
int ret;
mutex_lock(&chip->io_lock);
pm860x_write_device(i2c, 0xFA, 0, &zero);
pm860x_write_device(i2c, 0xFB, 0, &zero);
pm860x_write_device(i2c, 0xFF, 0, &zero);
ret = pm860x_read_device(i2c, reg, 1, &value);
i2c_lock_adapter(i2c->adapter);
read_device(i2c, 0xFA, 0, &zero);
read_device(i2c, 0xFB, 0, &zero);
read_device(i2c, 0xFF, 0, &zero);
ret = read_device(i2c, reg, 1, &value);
if (ret < 0)
goto out;
value &= ~mask;
value |= data;
ret = pm860x_write_device(i2c, reg, 1, &value);
ret = write_device(i2c, reg, 1, &value);
out:
pm860x_write_device(i2c, 0xFE, 0, &zero);
pm860x_write_device(i2c, 0xFC, 0, &zero);
mutex_unlock(&chip->io_lock);
read_device(i2c, 0xFE, 0, &zero);
read_device(i2c, 0xFC, 0, &zero);
i2c_unlock_adapter(i2c->adapter);
return ret;
}
EXPORT_SYMBOL(pm860x_page_set_bits);
@ -257,11 +259,17 @@ static int verify_addr(struct i2c_client *i2c)
return 0;
}
static struct regmap_config pm860x_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
};
static int __devinit pm860x_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct pm860x_platform_data *pdata = client->dev.platform_data;
struct pm860x_chip *chip;
int ret;
if (!pdata) {
pr_info("No platform data in %s!\n", __func__);
@ -273,10 +281,17 @@ static int __devinit pm860x_probe(struct i2c_client *client,
return -ENOMEM;
chip->id = verify_addr(client);
chip->regmap = regmap_init_i2c(client, &pm860x_regmap_config);
if (IS_ERR(chip->regmap)) {
ret = PTR_ERR(chip->regmap);
dev_err(&client->dev, "Failed to allocate register map: %d\n",
ret);
kfree(chip);
return ret;
}
chip->client = client;
i2c_set_clientdata(client, chip);
chip->dev = &client->dev;
mutex_init(&chip->io_lock);
dev_set_drvdata(chip->dev, chip);
/*
@ -290,6 +305,14 @@ static int __devinit pm860x_probe(struct i2c_client *client,
chip->companion_addr = pdata->companion_addr;
chip->companion = i2c_new_dummy(chip->client->adapter,
chip->companion_addr);
chip->regmap_companion = regmap_init_i2c(chip->companion,
&pm860x_regmap_config);
if (IS_ERR(chip->regmap_companion)) {
ret = PTR_ERR(chip->regmap_companion);
dev_err(&chip->companion->dev,
"Failed to allocate register map: %d\n", ret);
return ret;
}
i2c_set_clientdata(chip->companion, chip);
}
@ -302,7 +325,11 @@ static int __devexit pm860x_remove(struct i2c_client *client)
struct pm860x_chip *chip = i2c_get_clientdata(client);
pm860x_device_exit(chip);
i2c_unregister_device(chip->companion);
if (chip->companion) {
regmap_exit(chip->regmap_companion);
i2c_unregister_device(chip->companion);
}
regmap_exit(chip->regmap);
kfree(chip);
return 0;
}

View file

@ -12,6 +12,7 @@ config MFD_CORE
config MFD_88PM860X
bool "Support Marvell 88PM8606/88PM8607"
depends on I2C=y && GENERIC_HARDIRQS
select REGMAP_I2C
select MFD_CORE
help
This supports for Marvell 88PM8606/88PM8607 Power Management IC.
@ -199,7 +200,7 @@ config MENELAUS
config TWL4030_CORE
bool "Texas Instruments TWL4030/TWL5030/TWL6030/TPS659x0 Support"
depends on I2C=y && GENERIC_HARDIRQS
depends on I2C=y && GENERIC_HARDIRQS && IRQ_DOMAIN
help
Say yes here if you have TWL4030 / TWL6030 family chip on your board.
This core driver provides register access and IRQ handling
@ -257,7 +258,7 @@ config TWL6040_CORE
config MFD_STMPE
bool "Support STMicroelectronics STMPE"
depends on I2C=y && GENERIC_HARDIRQS
depends on (I2C=y || SPI_MASTER=y) && GENERIC_HARDIRQS
select MFD_CORE
help
Support for the STMPE family of I/O Expanders from
@ -278,6 +279,23 @@ config MFD_STMPE
Keypad: stmpe-keypad
Touchscreen: stmpe-ts
menu "STMPE Interface Drivers"
depends on MFD_STMPE
config STMPE_I2C
bool "STMPE I2C Inteface"
depends on I2C=y
default y
help
This is used to enable I2C interface of STMPE
config STMPE_SPI
bool "STMPE SPI Inteface"
depends on SPI_MASTER
help
This is used to enable SPI interface of STMPE
endmenu
config MFD_TC3589X
bool "Support Toshiba TC35892 and variants"
depends on I2C=y && GENERIC_HARDIRQS
@ -311,7 +329,7 @@ config MFD_TC6387XB
config MFD_TC6393XB
bool "Support Toshiba TC6393XB"
depends on GPIOLIB && ARM
depends on GPIOLIB && ARM && HAVE_CLK
select MFD_CORE
select MFD_TMIO
help
@ -399,6 +417,17 @@ config MFD_MAX8998
additional drivers must be enabled in order to use the functionality
of the device.
config MFD_S5M_CORE
bool "SAMSUNG S5M Series Support"
depends on I2C=y && GENERIC_HARDIRQS
select MFD_CORE
select REGMAP_I2C
help
Support for the Samsung Electronics S5M MFD series.
This driver provies common support for accessing the device,
additional drivers must be enabled in order to use the functionality
of the device
config MFD_WM8400
tristate "Support Wolfson Microelectronics WM8400"
select MFD_CORE

View file

@ -16,6 +16,8 @@ obj-$(CONFIG_MFD_DM355EVM_MSP) += dm355evm_msp.o
obj-$(CONFIG_MFD_TI_SSP) += ti-ssp.o
obj-$(CONFIG_MFD_STMPE) += stmpe.o
obj-$(CONFIG_STMPE_I2C) += stmpe-i2c.o
obj-$(CONFIG_STMPE_SPI) += stmpe-spi.o
obj-$(CONFIG_MFD_TC3589X) += tc3589x.o
obj-$(CONFIG_MFD_T7L66XB) += t7l66xb.o tmio_core.o
obj-$(CONFIG_MFD_TC6387XB) += tc6387xb.o tmio_core.o
@ -109,3 +111,4 @@ obj-$(CONFIG_MFD_PM8XXX_IRQ) += pm8xxx-irq.o
obj-$(CONFIG_TPS65911_COMPARATOR) += tps65911-comparator.o
obj-$(CONFIG_MFD_AAT2870_CORE) += aat2870-core.o
obj-$(CONFIG_MFD_INTEL_MSIC) += intel_msic.o
obj-$(CONFIG_MFD_S5M_CORE) += s5m-core.o s5m-irq.o

View file

@ -407,13 +407,13 @@ static int aat2870_i2c_probe(struct i2c_client *client,
aat2870->init(aat2870);
if (aat2870->en_pin >= 0) {
ret = gpio_request(aat2870->en_pin, "aat2870-en");
ret = gpio_request_one(aat2870->en_pin, GPIOF_OUT_INIT_HIGH,
"aat2870-en");
if (ret < 0) {
dev_err(&client->dev,
"Failed to request GPIO %d\n", aat2870->en_pin);
goto out_kfree;
}
gpio_direction_output(aat2870->en_pin, 1);
}
aat2870_enable(aat2870);
@ -468,9 +468,10 @@ static int aat2870_i2c_remove(struct i2c_client *client)
return 0;
}
#ifdef CONFIG_PM
static int aat2870_i2c_suspend(struct i2c_client *client, pm_message_t state)
#ifdef CONFIG_PM_SLEEP
static int aat2870_i2c_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct aat2870_data *aat2870 = i2c_get_clientdata(client);
aat2870_disable(aat2870);
@ -478,8 +479,9 @@ static int aat2870_i2c_suspend(struct i2c_client *client, pm_message_t state)
return 0;
}
static int aat2870_i2c_resume(struct i2c_client *client)
static int aat2870_i2c_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct aat2870_data *aat2870 = i2c_get_clientdata(client);
struct aat2870_register *reg = NULL;
int i;
@ -495,12 +497,12 @@ static int aat2870_i2c_resume(struct i2c_client *client)
return 0;
}
#else
#define aat2870_i2c_suspend NULL
#define aat2870_i2c_resume NULL
#endif /* CONFIG_PM */
#endif /* CONFIG_PM_SLEEP */
static struct i2c_device_id aat2870_i2c_id_table[] = {
static SIMPLE_DEV_PM_OPS(aat2870_pm_ops, aat2870_i2c_suspend,
aat2870_i2c_resume);
static const struct i2c_device_id aat2870_i2c_id_table[] = {
{ "aat2870", 0 },
{ }
};
@ -510,11 +512,10 @@ static struct i2c_driver aat2870_i2c_driver = {
.driver = {
.name = "aat2870",
.owner = THIS_MODULE,
.pm = &aat2870_pm_ops,
},
.probe = aat2870_i2c_probe,
.remove = aat2870_i2c_remove,
.suspend = aat2870_i2c_suspend,
.resume = aat2870_i2c_resume,
.id_table = aat2870_i2c_id_table,
};

View file

@ -22,8 +22,8 @@
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/random.h>
#include <linux/mfd/ab5500/ab5500.h>
#include <linux/mfd/abx500.h>
#include <linux/mfd/abx500/ab5500.h>
#include <linux/list.h>
#include <linux/bitops.h>
#include <linux/spinlock.h>

View file

@ -7,8 +7,8 @@
#include <linux/module.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include <linux/mfd/ab5500/ab5500.h>
#include <linux/mfd/abx500.h>
#include <linux/mfd/abx500/ab5500.h>
#include <linux/uaccess.h>
#include "ab5500-core.h"

View file

@ -17,7 +17,7 @@
#include <linux/platform_device.h>
#include <linux/mfd/core.h>
#include <linux/mfd/abx500.h>
#include <linux/mfd/ab8500.h>
#include <linux/mfd/abx500/ab8500.h>
#include <linux/regulator/ab8500.h>
/*

View file

@ -13,7 +13,7 @@
#include <linux/platform_device.h>
#include <linux/mfd/abx500.h>
#include <linux/mfd/ab8500.h>
#include <linux/mfd/abx500/ab8500.h>
static u32 debug_bank;
static u32 debug_address;

View file

@ -18,9 +18,9 @@
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/list.h>
#include <linux/mfd/ab8500.h>
#include <linux/mfd/abx500.h>
#include <linux/mfd/ab8500/gpadc.h>
#include <linux/mfd/abx500/ab8500.h>
#include <linux/mfd/abx500/ab8500-gpadc.h>
/*
* GPADC register offsets

View file

@ -10,7 +10,7 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/mfd/ab8500.h>
#include <linux/mfd/abx500/ab8500.h>
#include <linux/mfd/db8500-prcmu.h>
static int ab8500_i2c_write(struct ab8500 *ab8500, u16 addr, u8 data)

View file

@ -7,9 +7,9 @@
#include <linux/err.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/mfd/ab8500.h>
#include <linux/mfd/abx500.h>
#include <linux/mfd/ab8500/sysctrl.h>
#include <linux/mfd/abx500/ab8500.h>
#include <linux/mfd/abx500/ab8500-sysctrl.h>
static struct device *sysctrl_dev;

View file

@ -172,14 +172,14 @@ static void __devexit cs5535_mfd_remove(struct pci_dev *pdev)
pci_disable_device(pdev);
}
static struct pci_device_id cs5535_mfd_pci_tbl[] = {
static DEFINE_PCI_DEVICE_TABLE(cs5535_mfd_pci_tbl) = {
{ PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_ISA) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA) },
{ 0, }
};
MODULE_DEVICE_TABLE(pci, cs5535_mfd_pci_tbl);
static struct pci_driver cs5535_mfd_drv = {
static struct pci_driver cs5535_mfd_driver = {
.name = DRV_NAME,
.id_table = cs5535_mfd_pci_tbl,
.probe = cs5535_mfd_probe,
@ -188,12 +188,12 @@ static struct pci_driver cs5535_mfd_drv = {
static int __init cs5535_mfd_init(void)
{
return pci_register_driver(&cs5535_mfd_drv);
return pci_register_driver(&cs5535_mfd_driver);
}
static void __exit cs5535_mfd_exit(void)
{
pci_unregister_driver(&cs5535_mfd_drv);
pci_unregister_driver(&cs5535_mfd_driver);
}
module_init(cs5535_mfd_init);

View file

@ -308,8 +308,7 @@ static int add_children(struct i2c_client *client)
for (i = 0; i < ARRAY_SIZE(config_inputs); i++) {
int gpio = dm355evm_msp_gpio.base + config_inputs[i].offset;
gpio_request(gpio, config_inputs[i].label);
gpio_direction_input(gpio);
gpio_request_one(gpio, GPIOF_IN, config_inputs[i].label);
/* make it easy for userspace to see these */
gpio_export(gpio, false);

View file

@ -485,17 +485,7 @@ static struct platform_driver intel_msic_driver = {
},
};
static int __init intel_msic_init(void)
{
return platform_driver_register(&intel_msic_driver);
}
module_init(intel_msic_init);
static void __exit intel_msic_exit(void)
{
platform_driver_unregister(&intel_msic_driver);
}
module_exit(intel_msic_exit);
module_platform_driver(intel_msic_driver);
MODULE_DESCRIPTION("Driver for Intel MSIC");
MODULE_AUTHOR("Mika Westerberg <mika.westerberg@linux.intel.com>");

View file

@ -181,7 +181,7 @@ static struct resource jz4740_battery_resources[] = {
},
};
const struct mfd_cell jz4740_adc_cells[] = {
static struct mfd_cell jz4740_adc_cells[] = {
{
.id = 0,
.name = "jz4740-hwmon",
@ -338,17 +338,7 @@ static struct platform_driver jz4740_adc_driver = {
},
};
static int __init jz4740_adc_init(void)
{
return platform_driver_register(&jz4740_adc_driver);
}
module_init(jz4740_adc_init);
static void __exit jz4740_adc_exit(void)
{
platform_driver_unregister(&jz4740_adc_driver);
}
module_exit(jz4740_adc_exit);
module_platform_driver(jz4740_adc_driver);
MODULE_DESCRIPTION("JZ4740 SoC ADC driver");
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");

View file

@ -74,7 +74,7 @@ static struct mfd_cell tunnelcreek_cells[] = {
},
};
static struct pci_device_id lpc_sch_ids[] = {
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) },
{ 0, }

View file

@ -161,6 +161,8 @@ static int __devinit max8925_probe(struct i2c_client *client,
chip->adc = i2c_new_dummy(chip->i2c->adapter, ADC_I2C_ADDR);
i2c_set_clientdata(chip->adc, chip);
device_init_wakeup(&client->dev, 1);
max8925_device_init(chip, pdata);
return 0;
@ -177,10 +179,35 @@ static int __devexit max8925_remove(struct i2c_client *client)
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int max8925_suspend(struct device *dev)
{
struct i2c_client *client = container_of(dev, struct i2c_client, dev);
struct max8925_chip *chip = i2c_get_clientdata(client);
if (device_may_wakeup(dev) && chip->wakeup_flag)
enable_irq_wake(chip->core_irq);
return 0;
}
static int max8925_resume(struct device *dev)
{
struct i2c_client *client = container_of(dev, struct i2c_client, dev);
struct max8925_chip *chip = i2c_get_clientdata(client);
if (device_may_wakeup(dev) && chip->wakeup_flag)
disable_irq_wake(chip->core_irq);
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(max8925_pm_ops, max8925_suspend, max8925_resume);
static struct i2c_driver max8925_driver = {
.driver = {
.name = "max8925",
.owner = THIS_MODULE,
.pm = &max8925_pm_ops,
},
.probe = max8925_probe,
.remove = __devexit_p(max8925_remove),

View file

@ -43,7 +43,8 @@ static struct mfd_cell max8997_devs[] = {
{ .name = "max8997-battery", },
{ .name = "max8997-haptic", },
{ .name = "max8997-muic", },
{ .name = "max8997-flash", },
{ .name = "max8997-led", .id = 1 },
{ .name = "max8997-led", .id = 2 },
};
int max8997_read_reg(struct i2c_client *i2c, u8 reg, u8 *dest)

View file

@ -176,6 +176,8 @@ static int max8998_i2c_probe(struct i2c_client *i2c,
if (ret < 0)
goto err;
device_init_wakeup(max8998->dev, max8998->wakeup);
return ret;
err:
@ -210,7 +212,7 @@ static int max8998_suspend(struct device *dev)
struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
struct max8998_dev *max8998 = i2c_get_clientdata(i2c);
if (max8998->wakeup)
if (device_may_wakeup(dev))
irq_set_irq_wake(max8998->irq, 1);
return 0;
}
@ -220,7 +222,7 @@ static int max8998_resume(struct device *dev)
struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
struct max8998_dev *max8998 = i2c_get_clientdata(i2c);
if (max8998->wakeup)
if (device_may_wakeup(dev))
irq_set_irq_wake(max8998->irq, 0);
/*
* In LP3974, if IRQ registers are not "read & clear"

View file

@ -18,11 +18,15 @@
#include <linux/spi/spi.h>
#include <linux/mfd/core.h>
#include <linux/mfd/mc13xxx.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
struct mc13xxx {
struct spi_device *spidev;
struct mutex lock;
int irq;
int flags;
irq_handler_t irqhandler[MC13XXX_NUM_IRQ];
void *irqdata[MC13XXX_NUM_IRQ];
@ -550,10 +554,7 @@ static const char *mc13xxx_get_chipname(struct mc13xxx *mc13xxx)
int mc13xxx_get_flags(struct mc13xxx *mc13xxx)
{
struct mc13xxx_platform_data *pdata =
dev_get_platdata(&mc13xxx->spidev->dev);
return pdata->flags;
return mc13xxx->flags;
}
EXPORT_SYMBOL(mc13xxx_get_flags);
@ -615,13 +616,13 @@ int mc13xxx_adc_do_conversion(struct mc13xxx *mc13xxx, unsigned int mode,
break;
case MC13XXX_ADC_MODE_SINGLE_CHAN:
adc0 |= old_adc0 & MC13XXX_ADC0_TSMOD_MASK;
adc0 |= old_adc0 & MC13XXX_ADC0_CONFIG_MASK;
adc1 |= (channel & 0x7) << MC13XXX_ADC1_CHAN0_SHIFT;
adc1 |= MC13XXX_ADC1_RAND;
break;
case MC13XXX_ADC_MODE_MULT_CHAN:
adc0 |= old_adc0 & MC13XXX_ADC0_TSMOD_MASK;
adc0 |= old_adc0 & MC13XXX_ADC0_CONFIG_MASK;
adc1 |= 4 << MC13XXX_ADC1_CHAN1_SHIFT;
break;
@ -696,17 +697,67 @@ static int mc13xxx_add_subdevice(struct mc13xxx *mc13xxx, const char *format)
return mc13xxx_add_subdevice_pdata(mc13xxx, format, NULL, 0);
}
#ifdef CONFIG_OF
static int mc13xxx_probe_flags_dt(struct mc13xxx *mc13xxx)
{
struct device_node *np = mc13xxx->spidev->dev.of_node;
if (!np)
return -ENODEV;
if (of_get_property(np, "fsl,mc13xxx-uses-adc", NULL))
mc13xxx->flags |= MC13XXX_USE_ADC;
if (of_get_property(np, "fsl,mc13xxx-uses-codec", NULL))
mc13xxx->flags |= MC13XXX_USE_CODEC;
if (of_get_property(np, "fsl,mc13xxx-uses-rtc", NULL))
mc13xxx->flags |= MC13XXX_USE_RTC;
if (of_get_property(np, "fsl,mc13xxx-uses-touch", NULL))
mc13xxx->flags |= MC13XXX_USE_TOUCHSCREEN;
return 0;
}
#else
static inline int mc13xxx_probe_flags_dt(struct mc13xxx *mc13xxx)
{
return -ENODEV;
}
#endif
static const struct spi_device_id mc13xxx_device_id[] = {
{
.name = "mc13783",
.driver_data = MC13XXX_ID_MC13783,
}, {
.name = "mc13892",
.driver_data = MC13XXX_ID_MC13892,
}, {
/* sentinel */
}
};
MODULE_DEVICE_TABLE(spi, mc13xxx_device_id);
static const struct of_device_id mc13xxx_dt_ids[] = {
{ .compatible = "fsl,mc13783", .data = (void *) MC13XXX_ID_MC13783, },
{ .compatible = "fsl,mc13892", .data = (void *) MC13XXX_ID_MC13892, },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, mc13xxx_dt_ids);
static int mc13xxx_probe(struct spi_device *spi)
{
const struct of_device_id *of_id;
struct spi_driver *sdrv = to_spi_driver(spi->dev.driver);
struct mc13xxx *mc13xxx;
struct mc13xxx_platform_data *pdata = dev_get_platdata(&spi->dev);
enum mc13xxx_id id;
int ret;
if (!pdata) {
dev_err(&spi->dev, "invalid platform data\n");
return -EINVAL;
}
of_id = of_match_device(mc13xxx_dt_ids, &spi->dev);
if (of_id)
sdrv->id_table = &mc13xxx_device_id[(enum mc13xxx_id) of_id->data];
mc13xxx = kzalloc(sizeof(*mc13xxx), GFP_KERNEL);
if (!mc13xxx)
@ -749,28 +800,33 @@ err_revision:
mc13xxx_unlock(mc13xxx);
if (pdata->flags & MC13XXX_USE_ADC)
if (mc13xxx_probe_flags_dt(mc13xxx) < 0 && pdata)
mc13xxx->flags = pdata->flags;
if (mc13xxx->flags & MC13XXX_USE_ADC)
mc13xxx_add_subdevice(mc13xxx, "%s-adc");
if (pdata->flags & MC13XXX_USE_CODEC)
if (mc13xxx->flags & MC13XXX_USE_CODEC)
mc13xxx_add_subdevice(mc13xxx, "%s-codec");
mc13xxx_add_subdevice_pdata(mc13xxx, "%s-regulator",
&pdata->regulators, sizeof(pdata->regulators));
if (pdata->flags & MC13XXX_USE_RTC)
if (mc13xxx->flags & MC13XXX_USE_RTC)
mc13xxx_add_subdevice(mc13xxx, "%s-rtc");
if (pdata->flags & MC13XXX_USE_TOUCHSCREEN)
if (mc13xxx->flags & MC13XXX_USE_TOUCHSCREEN)
mc13xxx_add_subdevice(mc13xxx, "%s-ts");
if (pdata->leds)
if (pdata) {
mc13xxx_add_subdevice_pdata(mc13xxx, "%s-regulator",
&pdata->regulators, sizeof(pdata->regulators));
mc13xxx_add_subdevice_pdata(mc13xxx, "%s-led",
pdata->leds, sizeof(*pdata->leds));
if (pdata->buttons)
mc13xxx_add_subdevice_pdata(mc13xxx, "%s-pwrbutton",
pdata->buttons, sizeof(*pdata->buttons));
} else {
mc13xxx_add_subdevice(mc13xxx, "%s-regulator");
mc13xxx_add_subdevice(mc13xxx, "%s-led");
mc13xxx_add_subdevice(mc13xxx, "%s-pwrbutton");
}
return 0;
}
@ -788,25 +844,12 @@ static int __devexit mc13xxx_remove(struct spi_device *spi)
return 0;
}
static const struct spi_device_id mc13xxx_device_id[] = {
{
.name = "mc13783",
.driver_data = MC13XXX_ID_MC13783,
}, {
.name = "mc13892",
.driver_data = MC13XXX_ID_MC13892,
}, {
/* sentinel */
}
};
MODULE_DEVICE_TABLE(spi, mc13xxx_device_id);
static struct spi_driver mc13xxx_driver = {
.id_table = mc13xxx_device_id,
.driver = {
.name = "mc13xxx",
.bus = &spi_bus_type,
.owner = THIS_MODULE,
.of_match_table = mc13xxx_dt_ids,
},
.probe = mc13xxx_probe,
.remove = __devexit_p(mc13xxx_remove),

View file

@ -26,9 +26,35 @@
#define to_mcp(d) container_of(d, struct mcp, attached_device)
#define to_mcp_driver(d) container_of(d, struct mcp_driver, drv)
static const struct mcp_device_id *mcp_match_id(const struct mcp_device_id *id,
const char *codec)
{
while (id->name[0]) {
if (strcmp(codec, id->name) == 0)
return id;
id++;
}
return NULL;
}
const struct mcp_device_id *mcp_get_device_id(const struct mcp *mcp)
{
const struct mcp_driver *driver =
to_mcp_driver(mcp->attached_device.driver);
return mcp_match_id(driver->id_table, mcp->codec);
}
EXPORT_SYMBOL(mcp_get_device_id);
static int mcp_bus_match(struct device *dev, struct device_driver *drv)
{
return 1;
const struct mcp *mcp = to_mcp(dev);
const struct mcp_driver *driver = to_mcp_driver(drv);
if (driver->id_table)
return !!mcp_match_id(driver->id_table, mcp->codec);
return 0;
}
static int mcp_bus_probe(struct device *dev)
@ -74,9 +100,18 @@ static int mcp_bus_resume(struct device *dev)
return ret;
}
static int mcp_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct mcp *mcp = to_mcp(dev);
add_uevent_var(env, "MODALIAS=%s%s", MCP_MODULE_PREFIX, mcp->codec);
return 0;
}
static struct bus_type mcp_bus_type = {
.name = "mcp",
.match = mcp_bus_match,
.uevent = mcp_bus_uevent,
.probe = mcp_bus_probe,
.remove = mcp_bus_remove,
.suspend = mcp_bus_suspend,
@ -212,9 +247,14 @@ struct mcp *mcp_host_alloc(struct device *parent, size_t size)
}
EXPORT_SYMBOL(mcp_host_alloc);
int mcp_host_register(struct mcp *mcp)
int mcp_host_register(struct mcp *mcp, void *pdata)
{
if (!mcp->codec)
return -EINVAL;
mcp->attached_device.platform_data = pdata;
dev_set_name(&mcp->attached_device, "mcp0");
request_module("%s%s", MCP_MODULE_PREFIX, mcp->codec);
return device_register(&mcp->attached_device);
}
EXPORT_SYMBOL(mcp_host_register);

View file

@ -19,6 +19,7 @@
#include <linux/spinlock.h>
#include <linux/platform_device.h>
#include <linux/mfd/mcp.h>
#include <linux/io.h>
#include <mach/dma.h>
#include <mach/hardware.h>
@ -26,12 +27,19 @@
#include <asm/system.h>
#include <mach/mcp.h>
#include <mach/assabet.h>
/* Register offsets */
#define MCCR0 0x00
#define MCDR0 0x08
#define MCDR1 0x0C
#define MCDR2 0x10
#define MCSR 0x18
#define MCCR1 0x00
struct mcp_sa11x0 {
u32 mccr0;
u32 mccr1;
u32 mccr0;
u32 mccr1;
unsigned char *mccr0_base;
unsigned char *mccr1_base;
};
#define priv(mcp) ((struct mcp_sa11x0 *)mcp_priv(mcp))
@ -39,25 +47,25 @@ struct mcp_sa11x0 {
static void
mcp_sa11x0_set_telecom_divisor(struct mcp *mcp, unsigned int divisor)
{
unsigned int mccr0;
struct mcp_sa11x0 *priv = priv(mcp);
divisor /= 32;
mccr0 = Ser4MCCR0 & ~0x00007f00;
mccr0 |= divisor << 8;
Ser4MCCR0 = mccr0;
priv->mccr0 &= ~0x00007f00;
priv->mccr0 |= divisor << 8;
__raw_writel(priv->mccr0, priv->mccr0_base + MCCR0);
}
static void
mcp_sa11x0_set_audio_divisor(struct mcp *mcp, unsigned int divisor)
{
unsigned int mccr0;
struct mcp_sa11x0 *priv = priv(mcp);
divisor /= 32;
mccr0 = Ser4MCCR0 & ~0x0000007f;
mccr0 |= divisor;
Ser4MCCR0 = mccr0;
priv->mccr0 &= ~0x0000007f;
priv->mccr0 |= divisor;
__raw_writel(priv->mccr0, priv->mccr0_base + MCCR0);
}
/*
@ -71,12 +79,16 @@ mcp_sa11x0_write(struct mcp *mcp, unsigned int reg, unsigned int val)
{
int ret = -ETIME;
int i;
u32 mcpreg;
struct mcp_sa11x0 *priv = priv(mcp);
Ser4MCDR2 = reg << 17 | MCDR2_Wr | (val & 0xffff);
mcpreg = reg << 17 | MCDR2_Wr | (val & 0xffff);
__raw_writel(mcpreg, priv->mccr0_base + MCDR2);
for (i = 0; i < 2; i++) {
udelay(mcp->rw_timeout);
if (Ser4MCSR & MCSR_CWC) {
mcpreg = __raw_readl(priv->mccr0_base + MCSR);
if (mcpreg & MCSR_CWC) {
ret = 0;
break;
}
@ -97,13 +109,18 @@ mcp_sa11x0_read(struct mcp *mcp, unsigned int reg)
{
int ret = -ETIME;
int i;
u32 mcpreg;
struct mcp_sa11x0 *priv = priv(mcp);
Ser4MCDR2 = reg << 17 | MCDR2_Rd;
mcpreg = reg << 17 | MCDR2_Rd;
__raw_writel(mcpreg, priv->mccr0_base + MCDR2);
for (i = 0; i < 2; i++) {
udelay(mcp->rw_timeout);
if (Ser4MCSR & MCSR_CRC) {
ret = Ser4MCDR2 & 0xffff;
mcpreg = __raw_readl(priv->mccr0_base + MCSR);
if (mcpreg & MCSR_CRC) {
ret = __raw_readl(priv->mccr0_base + MCDR2)
& 0xffff;
break;
}
}
@ -116,13 +133,19 @@ mcp_sa11x0_read(struct mcp *mcp, unsigned int reg)
static void mcp_sa11x0_enable(struct mcp *mcp)
{
Ser4MCSR = -1;
Ser4MCCR0 |= MCCR0_MCE;
struct mcp_sa11x0 *priv = priv(mcp);
__raw_writel(-1, priv->mccr0_base + MCSR);
priv->mccr0 |= MCCR0_MCE;
__raw_writel(priv->mccr0, priv->mccr0_base + MCCR0);
}
static void mcp_sa11x0_disable(struct mcp *mcp)
{
Ser4MCCR0 &= ~MCCR0_MCE;
struct mcp_sa11x0 *priv = priv(mcp);
priv->mccr0 &= ~MCCR0_MCE;
__raw_writel(priv->mccr0, priv->mccr0_base + MCCR0);
}
/*
@ -142,50 +165,69 @@ static int mcp_sa11x0_probe(struct platform_device *pdev)
struct mcp_plat_data *data = pdev->dev.platform_data;
struct mcp *mcp;
int ret;
struct mcp_sa11x0 *priv;
struct resource *res_mem0, *res_mem1;
u32 size0, size1;
if (!data)
return -ENODEV;
if (!request_mem_region(0x80060000, 0x60, "sa11x0-mcp"))
if (!data->codec)
return -ENODEV;
res_mem0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res_mem0)
return -ENODEV;
size0 = res_mem0->end - res_mem0->start + 1;
res_mem1 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
if (!res_mem1)
return -ENODEV;
size1 = res_mem1->end - res_mem1->start + 1;
if (!request_mem_region(res_mem0->start, size0, "sa11x0-mcp"))
return -EBUSY;
if (!request_mem_region(res_mem1->start, size1, "sa11x0-mcp")) {
ret = -EBUSY;
goto release;
}
mcp = mcp_host_alloc(&pdev->dev, sizeof(struct mcp_sa11x0));
if (!mcp) {
ret = -ENOMEM;
goto release;
goto release2;
}
priv = priv(mcp);
mcp->owner = THIS_MODULE;
mcp->ops = &mcp_sa11x0;
mcp->sclk_rate = data->sclk_rate;
mcp->dma_audio_rd = DMA_Ser4MCP0Rd;
mcp->dma_audio_wr = DMA_Ser4MCP0Wr;
mcp->dma_telco_rd = DMA_Ser4MCP1Rd;
mcp->dma_telco_wr = DMA_Ser4MCP1Wr;
mcp->gpio_base = data->gpio_base;
mcp->dma_audio_rd = DDAR_DevAdd(res_mem0->start + MCDR0)
+ DDAR_DevRd + DDAR_Brst4 + DDAR_8BitDev;
mcp->dma_audio_wr = DDAR_DevAdd(res_mem0->start + MCDR0)
+ DDAR_DevWr + DDAR_Brst4 + DDAR_8BitDev;
mcp->dma_telco_rd = DDAR_DevAdd(res_mem0->start + MCDR1)
+ DDAR_DevRd + DDAR_Brst4 + DDAR_8BitDev;
mcp->dma_telco_wr = DDAR_DevAdd(res_mem0->start + MCDR1)
+ DDAR_DevWr + DDAR_Brst4 + DDAR_8BitDev;
mcp->codec = data->codec;
platform_set_drvdata(pdev, mcp);
if (machine_is_assabet()) {
ASSABET_BCR_set(ASSABET_BCR_CODEC_RST);
}
/*
* Setup the PPC unit correctly.
*/
PPDR &= ~PPC_RXD4;
PPDR |= PPC_TXD4 | PPC_SCLK | PPC_SFRM;
PSDR |= PPC_RXD4;
PSDR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
PPSR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
/*
* Initialise device. Note that we initially
* set the sampling rate to minimum.
*/
Ser4MCSR = -1;
Ser4MCCR1 = data->mccr1;
Ser4MCCR0 = data->mccr0 | 0x7f7f;
priv->mccr0_base = ioremap(res_mem0->start, size0);
priv->mccr1_base = ioremap(res_mem1->start, size1);
__raw_writel(-1, priv->mccr0_base + MCSR);
priv->mccr1 = data->mccr1;
priv->mccr0 = data->mccr0 | 0x7f7f;
__raw_writel(priv->mccr0, priv->mccr0_base + MCCR0);
__raw_writel(priv->mccr1, priv->mccr1_base + MCCR1);
/*
* Calculate the read/write timeout (us) from the bit clock
@ -195,36 +237,53 @@ static int mcp_sa11x0_probe(struct platform_device *pdev)
mcp->rw_timeout = (64 * 3 * 1000000 + mcp->sclk_rate - 1) /
mcp->sclk_rate;
ret = mcp_host_register(mcp);
ret = mcp_host_register(mcp, data->codec_pdata);
if (ret == 0)
goto out;
release2:
release_mem_region(res_mem1->start, size1);
release:
release_mem_region(0x80060000, 0x60);
release_mem_region(res_mem0->start, size0);
platform_set_drvdata(pdev, NULL);
out:
return ret;
}
static int mcp_sa11x0_remove(struct platform_device *dev)
static int mcp_sa11x0_remove(struct platform_device *pdev)
{
struct mcp *mcp = platform_get_drvdata(dev);
struct mcp *mcp = platform_get_drvdata(pdev);
struct mcp_sa11x0 *priv = priv(mcp);
struct resource *res_mem;
u32 size;
platform_set_drvdata(dev, NULL);
platform_set_drvdata(pdev, NULL);
mcp_host_unregister(mcp);
release_mem_region(0x80060000, 0x60);
res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res_mem) {
size = res_mem->end - res_mem->start + 1;
release_mem_region(res_mem->start, size);
}
res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
if (res_mem) {
size = res_mem->end - res_mem->start + 1;
release_mem_region(res_mem->start, size);
}
iounmap(priv->mccr0_base);
iounmap(priv->mccr1_base);
return 0;
}
static int mcp_sa11x0_suspend(struct platform_device *dev, pm_message_t state)
{
struct mcp *mcp = platform_get_drvdata(dev);
struct mcp_sa11x0 *priv = priv(mcp);
u32 mccr0;
priv(mcp)->mccr0 = Ser4MCCR0;
priv(mcp)->mccr1 = Ser4MCCR1;
Ser4MCCR0 &= ~MCCR0_MCE;
mccr0 = priv->mccr0 & ~MCCR0_MCE;
__raw_writel(mccr0, priv->mccr0_base + MCCR0);
return 0;
}
@ -232,9 +291,10 @@ static int mcp_sa11x0_suspend(struct platform_device *dev, pm_message_t state)
static int mcp_sa11x0_resume(struct platform_device *dev)
{
struct mcp *mcp = platform_get_drvdata(dev);
struct mcp_sa11x0 *priv = priv(mcp);
Ser4MCCR1 = priv(mcp)->mccr1;
Ser4MCCR0 = priv(mcp)->mccr0;
__raw_writel(priv->mccr0, priv->mccr0_base + MCCR0);
__raw_writel(priv->mccr1, priv->mccr1_base + MCCR1);
return 0;
}
@ -251,24 +311,14 @@ static struct platform_driver mcp_sa11x0_driver = {
.resume = mcp_sa11x0_resume,
.driver = {
.name = "sa11x0-mcp",
.owner = THIS_MODULE,
},
};
/*
* This needs re-working
*/
static int __init mcp_sa11x0_init(void)
{
return platform_driver_register(&mcp_sa11x0_driver);
}
static void __exit mcp_sa11x0_exit(void)
{
platform_driver_unregister(&mcp_sa11x0_driver);
}
module_init(mcp_sa11x0_init);
module_exit(mcp_sa11x0_exit);
module_platform_driver(mcp_sa11x0_driver);
MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
MODULE_DESCRIPTION("SA11x0 multimedia communications port driver");

View file

@ -503,19 +503,13 @@ static void omap_usbhs_init(struct device *dev)
spin_lock_irqsave(&omap->lock, flags);
if (pdata->ehci_data->phy_reset) {
if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) {
gpio_request(pdata->ehci_data->reset_gpio_port[0],
"USB1 PHY reset");
gpio_direction_output
(pdata->ehci_data->reset_gpio_port[0], 0);
}
if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0]))
gpio_request_one(pdata->ehci_data->reset_gpio_port[0],
GPIOF_OUT_INIT_LOW, "USB1 PHY reset");
if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1])) {
gpio_request(pdata->ehci_data->reset_gpio_port[1],
"USB2 PHY reset");
gpio_direction_output
(pdata->ehci_data->reset_gpio_port[1], 0);
}
if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1]))
gpio_request_one(pdata->ehci_data->reset_gpio_port[1],
GPIOF_OUT_INIT_LOW, "USB2 PHY reset");
/* Hold the PHY in RESET for enough time till DIR is high */
udelay(10);

View file

@ -249,17 +249,7 @@ static struct platform_driver pcf50633_adc_driver = {
.remove = __devexit_p(pcf50633_adc_remove),
};
static int __init pcf50633_adc_init(void)
{
return platform_driver_register(&pcf50633_adc_driver);
}
module_init(pcf50633_adc_init);
static void __exit pcf50633_adc_exit(void)
{
platform_driver_unregister(&pcf50633_adc_driver);
}
module_exit(pcf50633_adc_exit);
module_platform_driver(pcf50633_adc_driver);
MODULE_AUTHOR("Balaji Rao <balajirrao@openmoko.org>");
MODULE_DESCRIPTION("PCF50633 adc driver");

176
drivers/mfd/s5m-core.c Normal file
View file

@ -0,0 +1,176 @@
/*
* s5m87xx.c
*
* Copyright (c) 2011 Samsung Electronics Co., Ltd
* http://www.samsung.com
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/pm_runtime.h>
#include <linux/mutex.h>
#include <linux/mfd/core.h>
#include <linux/mfd/s5m87xx/s5m-core.h>
#include <linux/mfd/s5m87xx/s5m-pmic.h>
#include <linux/mfd/s5m87xx/s5m-rtc.h>
#include <linux/regmap.h>
static struct mfd_cell s5m87xx_devs[] = {
{
.name = "s5m8767-pmic",
}, {
.name = "s5m-rtc",
},
};
int s5m_reg_read(struct s5m87xx_dev *s5m87xx, u8 reg, void *dest)
{
return regmap_read(s5m87xx->regmap, reg, dest);
}
EXPORT_SYMBOL_GPL(s5m_reg_read);
int s5m_bulk_read(struct s5m87xx_dev *s5m87xx, u8 reg, int count, u8 *buf)
{
return regmap_bulk_read(s5m87xx->regmap, reg, buf, count);;
}
EXPORT_SYMBOL_GPL(s5m_bulk_read);
int s5m_reg_write(struct s5m87xx_dev *s5m87xx, u8 reg, u8 value)
{
return regmap_write(s5m87xx->regmap, reg, value);
}
EXPORT_SYMBOL_GPL(s5m_reg_write);
int s5m_bulk_write(struct s5m87xx_dev *s5m87xx, u8 reg, int count, u8 *buf)
{
return regmap_raw_write(s5m87xx->regmap, reg, buf, count * sizeof(u16));
}
EXPORT_SYMBOL_GPL(s5m_bulk_write);
int s5m_reg_update(struct s5m87xx_dev *s5m87xx, u8 reg, u8 val, u8 mask)
{
return regmap_update_bits(s5m87xx->regmap, reg, mask, val);
}
EXPORT_SYMBOL_GPL(s5m_reg_update);
static struct regmap_config s5m_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
};
static int s5m87xx_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct s5m_platform_data *pdata = i2c->dev.platform_data;
struct s5m87xx_dev *s5m87xx;
int ret = 0;
int error;
s5m87xx = kzalloc(sizeof(struct s5m87xx_dev), GFP_KERNEL);
if (s5m87xx == NULL)
return -ENOMEM;
i2c_set_clientdata(i2c, s5m87xx);
s5m87xx->dev = &i2c->dev;
s5m87xx->i2c = i2c;
s5m87xx->irq = i2c->irq;
s5m87xx->type = id->driver_data;
if (pdata) {
s5m87xx->device_type = pdata->device_type;
s5m87xx->ono = pdata->ono;
s5m87xx->irq_base = pdata->irq_base;
s5m87xx->wakeup = pdata->wakeup;
}
s5m87xx->regmap = regmap_init_i2c(i2c, &s5m_regmap_config);
if (IS_ERR(s5m87xx->regmap)) {
error = PTR_ERR(s5m87xx->regmap);
dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
error);
goto err;
}
s5m87xx->rtc = i2c_new_dummy(i2c->adapter, RTC_I2C_ADDR);
i2c_set_clientdata(s5m87xx->rtc, s5m87xx);
if (pdata->cfg_pmic_irq)
pdata->cfg_pmic_irq();
s5m_irq_init(s5m87xx);
pm_runtime_set_active(s5m87xx->dev);
ret = mfd_add_devices(s5m87xx->dev, -1,
s5m87xx_devs, ARRAY_SIZE(s5m87xx_devs),
NULL, 0);
if (ret < 0)
goto err;
return ret;
err:
mfd_remove_devices(s5m87xx->dev);
s5m_irq_exit(s5m87xx);
i2c_unregister_device(s5m87xx->rtc);
regmap_exit(s5m87xx->regmap);
kfree(s5m87xx);
return ret;
}
static int s5m87xx_i2c_remove(struct i2c_client *i2c)
{
struct s5m87xx_dev *s5m87xx = i2c_get_clientdata(i2c);
mfd_remove_devices(s5m87xx->dev);
s5m_irq_exit(s5m87xx);
i2c_unregister_device(s5m87xx->rtc);
regmap_exit(s5m87xx->regmap);
kfree(s5m87xx);
return 0;
}
static const struct i2c_device_id s5m87xx_i2c_id[] = {
{ "s5m87xx", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, s5m87xx_i2c_id);
static struct i2c_driver s5m87xx_i2c_driver = {
.driver = {
.name = "s5m87xx",
.owner = THIS_MODULE,
},
.probe = s5m87xx_i2c_probe,
.remove = s5m87xx_i2c_remove,
.id_table = s5m87xx_i2c_id,
};
static int __init s5m87xx_i2c_init(void)
{
return i2c_add_driver(&s5m87xx_i2c_driver);
}
subsys_initcall(s5m87xx_i2c_init);
static void __exit s5m87xx_i2c_exit(void)
{
i2c_del_driver(&s5m87xx_i2c_driver);
}
module_exit(s5m87xx_i2c_exit);
MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>");
MODULE_DESCRIPTION("Core support for the S5M MFD");
MODULE_LICENSE("GPL");

487
drivers/mfd/s5m-irq.c Normal file
View file

@ -0,0 +1,487 @@
/*
* s5m-irq.c
*
* Copyright (c) 2011 Samsung Electronics Co., Ltd
* http://www.samsung.com
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
*/
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/mfd/s5m87xx/s5m-core.h>
struct s5m_irq_data {
int reg;
int mask;
};
static struct s5m_irq_data s5m8767_irqs[] = {
[S5M8767_IRQ_PWRR] = {
.reg = 1,
.mask = S5M8767_IRQ_PWRR_MASK,
},
[S5M8767_IRQ_PWRF] = {
.reg = 1,
.mask = S5M8767_IRQ_PWRF_MASK,
},
[S5M8767_IRQ_PWR1S] = {
.reg = 1,
.mask = S5M8767_IRQ_PWR1S_MASK,
},
[S5M8767_IRQ_JIGR] = {
.reg = 1,
.mask = S5M8767_IRQ_JIGR_MASK,
},
[S5M8767_IRQ_JIGF] = {
.reg = 1,
.mask = S5M8767_IRQ_JIGF_MASK,
},
[S5M8767_IRQ_LOWBAT2] = {
.reg = 1,
.mask = S5M8767_IRQ_LOWBAT2_MASK,
},
[S5M8767_IRQ_LOWBAT1] = {
.reg = 1,
.mask = S5M8767_IRQ_LOWBAT1_MASK,
},
[S5M8767_IRQ_MRB] = {
.reg = 2,
.mask = S5M8767_IRQ_MRB_MASK,
},
[S5M8767_IRQ_DVSOK2] = {
.reg = 2,
.mask = S5M8767_IRQ_DVSOK2_MASK,
},
[S5M8767_IRQ_DVSOK3] = {
.reg = 2,
.mask = S5M8767_IRQ_DVSOK3_MASK,
},
[S5M8767_IRQ_DVSOK4] = {
.reg = 2,
.mask = S5M8767_IRQ_DVSOK4_MASK,
},
[S5M8767_IRQ_RTC60S] = {
.reg = 3,
.mask = S5M8767_IRQ_RTC60S_MASK,
},
[S5M8767_IRQ_RTCA1] = {
.reg = 3,
.mask = S5M8767_IRQ_RTCA1_MASK,
},
[S5M8767_IRQ_RTCA2] = {
.reg = 3,
.mask = S5M8767_IRQ_RTCA2_MASK,
},
[S5M8767_IRQ_SMPL] = {
.reg = 3,
.mask = S5M8767_IRQ_SMPL_MASK,
},
[S5M8767_IRQ_RTC1S] = {
.reg = 3,
.mask = S5M8767_IRQ_RTC1S_MASK,
},
[S5M8767_IRQ_WTSR] = {
.reg = 3,
.mask = S5M8767_IRQ_WTSR_MASK,
},
};
static struct s5m_irq_data s5m8763_irqs[] = {
[S5M8763_IRQ_DCINF] = {
.reg = 1,
.mask = S5M8763_IRQ_DCINF_MASK,
},
[S5M8763_IRQ_DCINR] = {
.reg = 1,
.mask = S5M8763_IRQ_DCINR_MASK,
},
[S5M8763_IRQ_JIGF] = {
.reg = 1,
.mask = S5M8763_IRQ_JIGF_MASK,
},
[S5M8763_IRQ_JIGR] = {
.reg = 1,
.mask = S5M8763_IRQ_JIGR_MASK,
},
[S5M8763_IRQ_PWRONF] = {
.reg = 1,
.mask = S5M8763_IRQ_PWRONF_MASK,
},
[S5M8763_IRQ_PWRONR] = {
.reg = 1,
.mask = S5M8763_IRQ_PWRONR_MASK,
},
[S5M8763_IRQ_WTSREVNT] = {
.reg = 2,
.mask = S5M8763_IRQ_WTSREVNT_MASK,
},
[S5M8763_IRQ_SMPLEVNT] = {
.reg = 2,
.mask = S5M8763_IRQ_SMPLEVNT_MASK,
},
[S5M8763_IRQ_ALARM1] = {
.reg = 2,
.mask = S5M8763_IRQ_ALARM1_MASK,
},
[S5M8763_IRQ_ALARM0] = {
.reg = 2,
.mask = S5M8763_IRQ_ALARM0_MASK,
},
[S5M8763_IRQ_ONKEY1S] = {
.reg = 3,
.mask = S5M8763_IRQ_ONKEY1S_MASK,
},
[S5M8763_IRQ_TOPOFFR] = {
.reg = 3,
.mask = S5M8763_IRQ_TOPOFFR_MASK,
},
[S5M8763_IRQ_DCINOVPR] = {
.reg = 3,
.mask = S5M8763_IRQ_DCINOVPR_MASK,
},
[S5M8763_IRQ_CHGRSTF] = {
.reg = 3,
.mask = S5M8763_IRQ_CHGRSTF_MASK,
},
[S5M8763_IRQ_DONER] = {
.reg = 3,
.mask = S5M8763_IRQ_DONER_MASK,
},
[S5M8763_IRQ_CHGFAULT] = {
.reg = 3,
.mask = S5M8763_IRQ_CHGFAULT_MASK,
},
[S5M8763_IRQ_LOBAT1] = {
.reg = 4,
.mask = S5M8763_IRQ_LOBAT1_MASK,
},
[S5M8763_IRQ_LOBAT2] = {
.reg = 4,
.mask = S5M8763_IRQ_LOBAT2_MASK,
},
};
static inline struct s5m_irq_data *
irq_to_s5m8767_irq(struct s5m87xx_dev *s5m87xx, int irq)
{
return &s5m8767_irqs[irq - s5m87xx->irq_base];
}
static void s5m8767_irq_lock(struct irq_data *data)
{
struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data);
mutex_lock(&s5m87xx->irqlock);
}
static void s5m8767_irq_sync_unlock(struct irq_data *data)
{
struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data);
int i;
for (i = 0; i < ARRAY_SIZE(s5m87xx->irq_masks_cur); i++) {
if (s5m87xx->irq_masks_cur[i] != s5m87xx->irq_masks_cache[i]) {
s5m87xx->irq_masks_cache[i] = s5m87xx->irq_masks_cur[i];
s5m_reg_write(s5m87xx, S5M8767_REG_INT1M + i,
s5m87xx->irq_masks_cur[i]);
}
}
mutex_unlock(&s5m87xx->irqlock);
}
static void s5m8767_irq_unmask(struct irq_data *data)
{
struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data);
struct s5m_irq_data *irq_data = irq_to_s5m8767_irq(s5m87xx,
data->irq);
s5m87xx->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask;
}
static void s5m8767_irq_mask(struct irq_data *data)
{
struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data);
struct s5m_irq_data *irq_data = irq_to_s5m8767_irq(s5m87xx,
data->irq);
s5m87xx->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask;
}
static struct irq_chip s5m8767_irq_chip = {
.name = "s5m8767",
.irq_bus_lock = s5m8767_irq_lock,
.irq_bus_sync_unlock = s5m8767_irq_sync_unlock,
.irq_mask = s5m8767_irq_mask,
.irq_unmask = s5m8767_irq_unmask,
};
static inline struct s5m_irq_data *
irq_to_s5m8763_irq(struct s5m87xx_dev *s5m87xx, int irq)
{
return &s5m8763_irqs[irq - s5m87xx->irq_base];
}
static void s5m8763_irq_lock(struct irq_data *data)
{
struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data);
mutex_lock(&s5m87xx->irqlock);
}
static void s5m8763_irq_sync_unlock(struct irq_data *data)
{
struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data);
int i;
for (i = 0; i < ARRAY_SIZE(s5m87xx->irq_masks_cur); i++) {
if (s5m87xx->irq_masks_cur[i] != s5m87xx->irq_masks_cache[i]) {
s5m87xx->irq_masks_cache[i] = s5m87xx->irq_masks_cur[i];
s5m_reg_write(s5m87xx, S5M8763_REG_IRQM1 + i,
s5m87xx->irq_masks_cur[i]);
}
}
mutex_unlock(&s5m87xx->irqlock);
}
static void s5m8763_irq_unmask(struct irq_data *data)
{
struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data);
struct s5m_irq_data *irq_data = irq_to_s5m8763_irq(s5m87xx,
data->irq);
s5m87xx->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask;
}
static void s5m8763_irq_mask(struct irq_data *data)
{
struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data);
struct s5m_irq_data *irq_data = irq_to_s5m8763_irq(s5m87xx,
data->irq);
s5m87xx->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask;
}
static struct irq_chip s5m8763_irq_chip = {
.name = "s5m8763",
.irq_bus_lock = s5m8763_irq_lock,
.irq_bus_sync_unlock = s5m8763_irq_sync_unlock,
.irq_mask = s5m8763_irq_mask,
.irq_unmask = s5m8763_irq_unmask,
};
static irqreturn_t s5m8767_irq_thread(int irq, void *data)
{
struct s5m87xx_dev *s5m87xx = data;
u8 irq_reg[NUM_IRQ_REGS-1];
int ret;
int i;
ret = s5m_bulk_read(s5m87xx, S5M8767_REG_INT1,
NUM_IRQ_REGS - 1, irq_reg);
if (ret < 0) {
dev_err(s5m87xx->dev, "Failed to read interrupt register: %d\n",
ret);
return IRQ_NONE;
}
for (i = 0; i < NUM_IRQ_REGS - 1; i++)
irq_reg[i] &= ~s5m87xx->irq_masks_cur[i];
for (i = 0; i < S5M8767_IRQ_NR; i++) {
if (irq_reg[s5m8767_irqs[i].reg - 1] & s5m8767_irqs[i].mask)
handle_nested_irq(s5m87xx->irq_base + i);
}
return IRQ_HANDLED;
}
static irqreturn_t s5m8763_irq_thread(int irq, void *data)
{
struct s5m87xx_dev *s5m87xx = data;
u8 irq_reg[NUM_IRQ_REGS];
int ret;
int i;
ret = s5m_bulk_read(s5m87xx, S5M8763_REG_IRQ1,
NUM_IRQ_REGS, irq_reg);
if (ret < 0) {
dev_err(s5m87xx->dev, "Failed to read interrupt register: %d\n",
ret);
return IRQ_NONE;
}
for (i = 0; i < NUM_IRQ_REGS; i++)
irq_reg[i] &= ~s5m87xx->irq_masks_cur[i];
for (i = 0; i < S5M8763_IRQ_NR; i++) {
if (irq_reg[s5m8763_irqs[i].reg - 1] & s5m8763_irqs[i].mask)
handle_nested_irq(s5m87xx->irq_base + i);
}
return IRQ_HANDLED;
}
int s5m_irq_resume(struct s5m87xx_dev *s5m87xx)
{
if (s5m87xx->irq && s5m87xx->irq_base){
switch (s5m87xx->device_type) {
case S5M8763X:
s5m8763_irq_thread(s5m87xx->irq_base, s5m87xx);
break;
case S5M8767X:
s5m8767_irq_thread(s5m87xx->irq_base, s5m87xx);
break;
default:
break;
}
}
return 0;
}
int s5m_irq_init(struct s5m87xx_dev *s5m87xx)
{
int i;
int cur_irq;
int ret = 0;
int type = s5m87xx->device_type;
if (!s5m87xx->irq) {
dev_warn(s5m87xx->dev,
"No interrupt specified, no interrupts\n");
s5m87xx->irq_base = 0;
return 0;
}
if (!s5m87xx->irq_base) {
dev_err(s5m87xx->dev,
"No interrupt base specified, no interrupts\n");
return 0;
}
mutex_init(&s5m87xx->irqlock);
switch (type) {
case S5M8763X:
for (i = 0; i < NUM_IRQ_REGS; i++) {
s5m87xx->irq_masks_cur[i] = 0xff;
s5m87xx->irq_masks_cache[i] = 0xff;
s5m_reg_write(s5m87xx, S5M8763_REG_IRQM1 + i,
0xff);
}
s5m_reg_write(s5m87xx, S5M8763_REG_STATUSM1, 0xff);
s5m_reg_write(s5m87xx, S5M8763_REG_STATUSM2, 0xff);
for (i = 0; i < S5M8763_IRQ_NR; i++) {
cur_irq = i + s5m87xx->irq_base;
irq_set_chip_data(cur_irq, s5m87xx);
irq_set_chip_and_handler(cur_irq, &s5m8763_irq_chip,
handle_edge_irq);
irq_set_nested_thread(cur_irq, 1);
#ifdef CONFIG_ARM
set_irq_flags(cur_irq, IRQF_VALID);
#else
irq_set_noprobe(cur_irq);
#endif
}
ret = request_threaded_irq(s5m87xx->irq, NULL,
s5m8763_irq_thread,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
"s5m87xx-irq", s5m87xx);
if (ret) {
dev_err(s5m87xx->dev, "Failed to request IRQ %d: %d\n",
s5m87xx->irq, ret);
return ret;
}
break;
case S5M8767X:
for (i = 0; i < NUM_IRQ_REGS - 1; i++) {
s5m87xx->irq_masks_cur[i] = 0xff;
s5m87xx->irq_masks_cache[i] = 0xff;
s5m_reg_write(s5m87xx, S5M8767_REG_INT1M + i,
0xff);
}
for (i = 0; i < S5M8767_IRQ_NR; i++) {
cur_irq = i + s5m87xx->irq_base;
irq_set_chip_data(cur_irq, s5m87xx);
if (ret) {
dev_err(s5m87xx->dev,
"Failed to irq_set_chip_data %d: %d\n",
s5m87xx->irq, ret);
return ret;
}
irq_set_chip_and_handler(cur_irq, &s5m8767_irq_chip,
handle_edge_irq);
irq_set_nested_thread(cur_irq, 1);
#ifdef CONFIG_ARM
set_irq_flags(cur_irq, IRQF_VALID);
#else
irq_set_noprobe(cur_irq);
#endif
}
ret = request_threaded_irq(s5m87xx->irq, NULL,
s5m8767_irq_thread,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
"s5m87xx-irq", s5m87xx);
if (ret) {
dev_err(s5m87xx->dev, "Failed to request IRQ %d: %d\n",
s5m87xx->irq, ret);
return ret;
}
break;
default:
break;
}
if (!s5m87xx->ono)
return 0;
switch (type) {
case S5M8763X:
ret = request_threaded_irq(s5m87xx->ono, NULL,
s5m8763_irq_thread,
IRQF_TRIGGER_FALLING |
IRQF_TRIGGER_RISING |
IRQF_ONESHOT, "s5m87xx-ono",
s5m87xx);
break;
case S5M8767X:
ret = request_threaded_irq(s5m87xx->ono, NULL,
s5m8767_irq_thread,
IRQF_TRIGGER_FALLING |
IRQF_TRIGGER_RISING |
IRQF_ONESHOT, "s5m87xx-ono", s5m87xx);
break;
default:
break;
}
if (ret)
dev_err(s5m87xx->dev, "Failed to request IRQ %d: %d\n",
s5m87xx->ono, ret);
return 0;
}
void s5m_irq_exit(struct s5m87xx_dev *s5m87xx)
{
if (s5m87xx->ono)
free_irq(s5m87xx->ono, s5m87xx);
if (s5m87xx->irq)
free_irq(s5m87xx->irq, s5m87xx);
}

View file

@ -1720,7 +1720,7 @@ static int sm501_plat_remove(struct platform_device *dev)
return 0;
}
static struct pci_device_id sm501_pci_tbl[] = {
static DEFINE_PCI_DEVICE_TABLE(sm501_pci_tbl) = {
{ 0x126f, 0x0501, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
{ 0, },
};

109
drivers/mfd/stmpe-i2c.c Normal file
View file

@ -0,0 +1,109 @@
/*
* ST Microelectronics MFD: stmpe's i2c client specific driver
*
* Copyright (C) ST-Ericsson SA 2010
* Copyright (C) ST Microelectronics SA 2011
*
* License Terms: GNU General Public License, version 2
* Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
* Author: Viresh Kumar <viresh.kumar@st.com> for ST Microelectronics
*/
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/types.h>
#include "stmpe.h"
static int i2c_reg_read(struct stmpe *stmpe, u8 reg)
{
struct i2c_client *i2c = stmpe->client;
return i2c_smbus_read_byte_data(i2c, reg);
}
static int i2c_reg_write(struct stmpe *stmpe, u8 reg, u8 val)
{
struct i2c_client *i2c = stmpe->client;
return i2c_smbus_write_byte_data(i2c, reg, val);
}
static int i2c_block_read(struct stmpe *stmpe, u8 reg, u8 length, u8 *values)
{
struct i2c_client *i2c = stmpe->client;
return i2c_smbus_read_i2c_block_data(i2c, reg, length, values);
}
static int i2c_block_write(struct stmpe *stmpe, u8 reg, u8 length,
const u8 *values)
{
struct i2c_client *i2c = stmpe->client;
return i2c_smbus_write_i2c_block_data(i2c, reg, length, values);
}
static struct stmpe_client_info i2c_ci = {
.read_byte = i2c_reg_read,
.write_byte = i2c_reg_write,
.read_block = i2c_block_read,
.write_block = i2c_block_write,
};
static int __devinit
stmpe_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
{
i2c_ci.data = (void *)id;
i2c_ci.irq = i2c->irq;
i2c_ci.client = i2c;
i2c_ci.dev = &i2c->dev;
return stmpe_probe(&i2c_ci, id->driver_data);
}
static int __devexit stmpe_i2c_remove(struct i2c_client *i2c)
{
struct stmpe *stmpe = dev_get_drvdata(&i2c->dev);
return stmpe_remove(stmpe);
}
static const struct i2c_device_id stmpe_i2c_id[] = {
{ "stmpe610", STMPE610 },
{ "stmpe801", STMPE801 },
{ "stmpe811", STMPE811 },
{ "stmpe1601", STMPE1601 },
{ "stmpe2401", STMPE2401 },
{ "stmpe2403", STMPE2403 },
{ }
};
MODULE_DEVICE_TABLE(i2c, stmpe_id);
static struct i2c_driver stmpe_i2c_driver = {
.driver.name = "stmpe-i2c",
.driver.owner = THIS_MODULE,
#ifdef CONFIG_PM
.driver.pm = &stmpe_dev_pm_ops,
#endif
.probe = stmpe_i2c_probe,
.remove = __devexit_p(stmpe_i2c_remove),
.id_table = stmpe_i2c_id,
};
static int __init stmpe_init(void)
{
return i2c_add_driver(&stmpe_i2c_driver);
}
subsys_initcall(stmpe_init);
static void __exit stmpe_exit(void)
{
i2c_del_driver(&stmpe_i2c_driver);
}
module_exit(stmpe_exit);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("STMPE MFD I2C Interface Driver");
MODULE_AUTHOR("Rabin Vincent <rabin.vincent@stericsson.com>");

150
drivers/mfd/stmpe-spi.c Normal file
View file

@ -0,0 +1,150 @@
/*
* ST Microelectronics MFD: stmpe's spi client specific driver
*
* Copyright (C) ST Microelectronics SA 2011
*
* License Terms: GNU General Public License, version 2
* Author: Viresh Kumar <viresh.kumar@st.com> for ST Microelectronics
*/
#include <linux/spi/spi.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/types.h>
#include "stmpe.h"
#define READ_CMD (1 << 7)
static int spi_reg_read(struct stmpe *stmpe, u8 reg)
{
struct spi_device *spi = stmpe->client;
int status = spi_w8r16(spi, reg | READ_CMD);
return (status < 0) ? status : status >> 8;
}
static int spi_reg_write(struct stmpe *stmpe, u8 reg, u8 val)
{
struct spi_device *spi = stmpe->client;
u16 cmd = (val << 8) | reg;
return spi_write(spi, (const u8 *)&cmd, 2);
}
static int spi_block_read(struct stmpe *stmpe, u8 reg, u8 length, u8 *values)
{
int ret, i;
for (i = 0; i < length; i++) {
ret = spi_reg_read(stmpe, reg + i);
if (ret < 0)
return ret;
*(values + i) = ret;
}
return 0;
}
static int spi_block_write(struct stmpe *stmpe, u8 reg, u8 length,
const u8 *values)
{
int ret = 0, i;
for (i = length; i > 0; i--, reg++) {
ret = spi_reg_write(stmpe, reg, *(values + i - 1));
if (ret < 0)
return ret;
}
return ret;
}
static void spi_init(struct stmpe *stmpe)
{
struct spi_device *spi = stmpe->client;
spi->bits_per_word = 8;
/* This register is only present for stmpe811 */
if (stmpe->variant->id_val == 0x0811)
spi_reg_write(stmpe, STMPE811_REG_SPI_CFG, spi->mode);
if (spi_setup(spi) < 0)
dev_dbg(&spi->dev, "spi_setup failed\n");
}
static struct stmpe_client_info spi_ci = {
.read_byte = spi_reg_read,
.write_byte = spi_reg_write,
.read_block = spi_block_read,
.write_block = spi_block_write,
.init = spi_init,
};
static int __devinit
stmpe_spi_probe(struct spi_device *spi)
{
const struct spi_device_id *id = spi_get_device_id(spi);
/* don't exceed max specified rate - 1MHz - Limitation of STMPE */
if (spi->max_speed_hz > 1000000) {
dev_dbg(&spi->dev, "f(sample) %d KHz?\n",
(spi->max_speed_hz/1000));
return -EINVAL;
}
spi_ci.irq = spi->irq;
spi_ci.client = spi;
spi_ci.dev = &spi->dev;
return stmpe_probe(&spi_ci, id->driver_data);
}
static int __devexit stmpe_spi_remove(struct spi_device *spi)
{
struct stmpe *stmpe = dev_get_drvdata(&spi->dev);
return stmpe_remove(stmpe);
}
static const struct spi_device_id stmpe_spi_id[] = {
{ "stmpe610", STMPE610 },
{ "stmpe801", STMPE801 },
{ "stmpe811", STMPE811 },
{ "stmpe1601", STMPE1601 },
{ "stmpe2401", STMPE2401 },
{ "stmpe2403", STMPE2403 },
{ }
};
MODULE_DEVICE_TABLE(spi, stmpe_id);
static struct spi_driver stmpe_spi_driver = {
.driver = {
.name = "stmpe-spi",
.bus = &spi_bus_type,
.owner = THIS_MODULE,
#ifdef CONFIG_PM
.pm = &stmpe_dev_pm_ops,
#endif
},
.probe = stmpe_spi_probe,
.remove = __devexit_p(stmpe_spi_remove),
.id_table = stmpe_spi_id,
};
static int __init stmpe_init(void)
{
return spi_register_driver(&stmpe_spi_driver);
}
subsys_initcall(stmpe_init);
static void __exit stmpe_exit(void)
{
spi_unregister_driver(&stmpe_spi_driver);
}
module_exit(stmpe_exit);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("STMPE MFD SPI Interface Driver");
MODULE_AUTHOR("Viresh Kumar <viresh.kumar@st.com>");

View file

@ -1,18 +1,20 @@
/*
* ST Microelectronics MFD: stmpe's driver
*
* Copyright (C) ST-Ericsson SA 2010
*
* License Terms: GNU General Public License, version 2
* Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
*/
#include <linux/gpio.h>
#include <linux/export.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/pm.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/mfd/core.h>
#include <linux/mfd/stmpe.h>
#include "stmpe.h"
static int __stmpe_enable(struct stmpe *stmpe, unsigned int blocks)
@ -29,10 +31,9 @@ static int __stmpe_reg_read(struct stmpe *stmpe, u8 reg)
{
int ret;
ret = i2c_smbus_read_byte_data(stmpe->i2c, reg);
ret = stmpe->ci->read_byte(stmpe, reg);
if (ret < 0)
dev_err(stmpe->dev, "failed to read reg %#x: %d\n",
reg, ret);
dev_err(stmpe->dev, "failed to read reg %#x: %d\n", reg, ret);
dev_vdbg(stmpe->dev, "rd: reg %#x => data %#x\n", reg, ret);
@ -45,10 +46,9 @@ static int __stmpe_reg_write(struct stmpe *stmpe, u8 reg, u8 val)
dev_vdbg(stmpe->dev, "wr: reg %#x <= %#x\n", reg, val);
ret = i2c_smbus_write_byte_data(stmpe->i2c, reg, val);
ret = stmpe->ci->write_byte(stmpe, reg, val);
if (ret < 0)
dev_err(stmpe->dev, "failed to write reg %#x: %d\n",
reg, ret);
dev_err(stmpe->dev, "failed to write reg %#x: %d\n", reg, ret);
return ret;
}
@ -72,10 +72,9 @@ static int __stmpe_block_read(struct stmpe *stmpe, u8 reg, u8 length,
{
int ret;
ret = i2c_smbus_read_i2c_block_data(stmpe->i2c, reg, length, values);
ret = stmpe->ci->read_block(stmpe, reg, length, values);
if (ret < 0)
dev_err(stmpe->dev, "failed to read regs %#x: %d\n",
reg, ret);
dev_err(stmpe->dev, "failed to read regs %#x: %d\n", reg, ret);
dev_vdbg(stmpe->dev, "rd: reg %#x (%d) => ret %#x\n", reg, length, ret);
stmpe_dump_bytes("stmpe rd: ", values, length);
@ -91,11 +90,9 @@ static int __stmpe_block_write(struct stmpe *stmpe, u8 reg, u8 length,
dev_vdbg(stmpe->dev, "wr: regs %#x (%d)\n", reg, length);
stmpe_dump_bytes("stmpe wr: ", values, length);
ret = i2c_smbus_write_i2c_block_data(stmpe->i2c, reg, length,
values);
ret = stmpe->ci->write_block(stmpe, reg, length, values);
if (ret < 0)
dev_err(stmpe->dev, "failed to write regs %#x: %d\n",
reg, ret);
dev_err(stmpe->dev, "failed to write regs %#x: %d\n", reg, ret);
return ret;
}
@ -245,12 +242,14 @@ int stmpe_set_altfunc(struct stmpe *stmpe, u32 pins, enum stmpe_block block)
u8 regaddr = stmpe->regs[STMPE_IDX_GPAFR_U_MSB];
int af_bits = variant->af_bits;
int numregs = DIV_ROUND_UP(stmpe->num_gpios * af_bits, 8);
int afperreg = 8 / af_bits;
int mask = (1 << af_bits) - 1;
u8 regs[numregs];
int af;
int ret;
int af, afperreg, ret;
if (!variant->get_altfunc)
return 0;
afperreg = 8 / af_bits;
mutex_lock(&stmpe->lock);
ret = __stmpe_enable(stmpe, STMPE_BLOCK_GPIO);
@ -325,7 +324,51 @@ static struct mfd_cell stmpe_keypad_cell = {
};
/*
* Touchscreen (STMPE811)
* STMPE801
*/
static const u8 stmpe801_regs[] = {
[STMPE_IDX_CHIP_ID] = STMPE801_REG_CHIP_ID,
[STMPE_IDX_ICR_LSB] = STMPE801_REG_SYS_CTRL,
[STMPE_IDX_GPMR_LSB] = STMPE801_REG_GPIO_MP_STA,
[STMPE_IDX_GPSR_LSB] = STMPE801_REG_GPIO_SET_PIN,
[STMPE_IDX_GPCR_LSB] = STMPE801_REG_GPIO_SET_PIN,
[STMPE_IDX_GPDR_LSB] = STMPE801_REG_GPIO_DIR,
[STMPE_IDX_IEGPIOR_LSB] = STMPE801_REG_GPIO_INT_EN,
[STMPE_IDX_ISGPIOR_MSB] = STMPE801_REG_GPIO_INT_STA,
};
static struct stmpe_variant_block stmpe801_blocks[] = {
{
.cell = &stmpe_gpio_cell,
.irq = 0,
.block = STMPE_BLOCK_GPIO,
},
};
static int stmpe801_enable(struct stmpe *stmpe, unsigned int blocks,
bool enable)
{
if (blocks & STMPE_BLOCK_GPIO)
return 0;
else
return -EINVAL;
}
static struct stmpe_variant_info stmpe801 = {
.name = "stmpe801",
.id_val = STMPE801_ID,
.id_mask = 0xffff,
.num_gpios = 8,
.regs = stmpe801_regs,
.blocks = stmpe801_blocks,
.num_blocks = ARRAY_SIZE(stmpe801_blocks),
.num_irqs = STMPE801_NR_INTERNAL_IRQS,
.enable = stmpe801_enable,
};
/*
* Touchscreen (STMPE811 or STMPE610)
*/
static struct resource stmpe_ts_resources[] = {
@ -350,7 +393,7 @@ static struct mfd_cell stmpe_ts_cell = {
};
/*
* STMPE811
* STMPE811 or STMPE610
*/
static const u8 stmpe811_regs[] = {
@ -421,6 +464,21 @@ static struct stmpe_variant_info stmpe811 = {
.get_altfunc = stmpe811_get_altfunc,
};
/* Similar to 811, except number of gpios */
static struct stmpe_variant_info stmpe610 = {
.name = "stmpe610",
.id_val = 0x0811,
.id_mask = 0xffff,
.num_gpios = 6,
.af_bits = 1,
.regs = stmpe811_regs,
.blocks = stmpe811_blocks,
.num_blocks = ARRAY_SIZE(stmpe811_blocks),
.num_irqs = STMPE811_NR_INTERNAL_IRQS,
.enable = stmpe811_enable,
.get_altfunc = stmpe811_get_altfunc,
};
/*
* STMPE1601
*/
@ -655,6 +713,8 @@ static struct stmpe_variant_info stmpe2403 = {
};
static struct stmpe_variant_info *stmpe_variant_info[] = {
[STMPE610] = &stmpe610,
[STMPE801] = &stmpe801,
[STMPE811] = &stmpe811,
[STMPE1601] = &stmpe1601,
[STMPE2401] = &stmpe2401,
@ -671,6 +731,11 @@ static irqreturn_t stmpe_irq(int irq, void *data)
int ret;
int i;
if (variant->id_val == STMPE801_ID) {
handle_nested_irq(stmpe->irq_base);
return IRQ_HANDLED;
}
ret = stmpe_block_read(stmpe, israddr, num, isr);
if (ret < 0)
return IRQ_NONE;
@ -757,14 +822,17 @@ static struct irq_chip stmpe_irq_chip = {
static int __devinit stmpe_irq_init(struct stmpe *stmpe)
{
struct irq_chip *chip = NULL;
int num_irqs = stmpe->variant->num_irqs;
int base = stmpe->irq_base;
int irq;
if (stmpe->variant->id_val != STMPE801_ID)
chip = &stmpe_irq_chip;
for (irq = base; irq < base + num_irqs; irq++) {
irq_set_chip_data(irq, stmpe);
irq_set_chip_and_handler(irq, &stmpe_irq_chip,
handle_edge_irq);
irq_set_chip_and_handler(irq, chip, handle_edge_irq);
irq_set_nested_thread(irq, 1);
#ifdef CONFIG_ARM
set_irq_flags(irq, IRQF_VALID);
@ -796,7 +864,7 @@ static int __devinit stmpe_chip_init(struct stmpe *stmpe)
unsigned int irq_trigger = stmpe->pdata->irq_trigger;
int autosleep_timeout = stmpe->pdata->autosleep_timeout;
struct stmpe_variant_info *variant = stmpe->variant;
u8 icr = STMPE_ICR_LSB_GIM;
u8 icr;
unsigned int id;
u8 data[2];
int ret;
@ -819,16 +887,32 @@ static int __devinit stmpe_chip_init(struct stmpe *stmpe)
if (ret)
return ret;
if (irq_trigger == IRQF_TRIGGER_FALLING ||
irq_trigger == IRQF_TRIGGER_RISING)
icr |= STMPE_ICR_LSB_EDGE;
if (id == STMPE801_ID)
icr = STMPE801_REG_SYS_CTRL_INT_EN;
else
icr = STMPE_ICR_LSB_GIM;
/* STMPE801 doesn't support Edge interrupts */
if (id != STMPE801_ID) {
if (irq_trigger == IRQF_TRIGGER_FALLING ||
irq_trigger == IRQF_TRIGGER_RISING)
icr |= STMPE_ICR_LSB_EDGE;
}
if (irq_trigger == IRQF_TRIGGER_RISING ||
irq_trigger == IRQF_TRIGGER_HIGH)
icr |= STMPE_ICR_LSB_HIGH;
irq_trigger == IRQF_TRIGGER_HIGH) {
if (id == STMPE801_ID)
icr |= STMPE801_REG_SYS_CTRL_INT_HI;
else
icr |= STMPE_ICR_LSB_HIGH;
}
if (stmpe->pdata->irq_invert_polarity)
icr ^= STMPE_ICR_LSB_HIGH;
if (stmpe->pdata->irq_invert_polarity) {
if (id == STMPE801_ID)
icr ^= STMPE801_REG_SYS_CTRL_INT_HI;
else
icr ^= STMPE_ICR_LSB_HIGH;
}
if (stmpe->pdata->autosleep) {
ret = stmpe_autosleep(stmpe, autosleep_timeout);
@ -873,32 +957,10 @@ static int __devinit stmpe_devices_init(struct stmpe *stmpe)
return ret;
}
#ifdef CONFIG_PM
static int stmpe_suspend(struct device *dev)
/* Called from client specific probe routines */
int __devinit stmpe_probe(struct stmpe_client_info *ci, int partnum)
{
struct i2c_client *i2c = to_i2c_client(dev);
if (device_may_wakeup(&i2c->dev))
enable_irq_wake(i2c->irq);
return 0;
}
static int stmpe_resume(struct device *dev)
{
struct i2c_client *i2c = to_i2c_client(dev);
if (device_may_wakeup(&i2c->dev))
disable_irq_wake(i2c->irq);
return 0;
}
#endif
static int __devinit stmpe_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct stmpe_platform_data *pdata = i2c->dev.platform_data;
struct stmpe_platform_data *pdata = dev_get_platdata(ci->dev);
struct stmpe *stmpe;
int ret;
@ -912,30 +974,43 @@ static int __devinit stmpe_probe(struct i2c_client *i2c,
mutex_init(&stmpe->irq_lock);
mutex_init(&stmpe->lock);
stmpe->dev = &i2c->dev;
stmpe->i2c = i2c;
stmpe->dev = ci->dev;
stmpe->client = ci->client;
stmpe->pdata = pdata;
stmpe->irq_base = pdata->irq_base;
stmpe->partnum = id->driver_data;
stmpe->variant = stmpe_variant_info[stmpe->partnum];
stmpe->ci = ci;
stmpe->partnum = partnum;
stmpe->variant = stmpe_variant_info[partnum];
stmpe->regs = stmpe->variant->regs;
stmpe->num_gpios = stmpe->variant->num_gpios;
dev_set_drvdata(stmpe->dev, stmpe);
i2c_set_clientdata(i2c, stmpe);
if (ci->init)
ci->init(stmpe);
if (pdata->irq_over_gpio) {
ret = gpio_request_one(pdata->irq_gpio, GPIOF_DIR_IN, "stmpe");
if (ret) {
dev_err(stmpe->dev, "failed to request IRQ GPIO: %d\n",
ret);
goto out_free;
}
stmpe->irq = gpio_to_irq(pdata->irq_gpio);
} else {
stmpe->irq = ci->irq;
}
ret = stmpe_chip_init(stmpe);
if (ret)
goto out_free;
goto free_gpio;
ret = stmpe_irq_init(stmpe);
if (ret)
goto out_free;
goto free_gpio;
ret = request_threaded_irq(stmpe->i2c->irq, NULL, stmpe_irq,
pdata->irq_trigger | IRQF_ONESHOT,
"stmpe", stmpe);
ret = request_threaded_irq(stmpe->irq, NULL, stmpe_irq,
pdata->irq_trigger | IRQF_ONESHOT, "stmpe", stmpe);
if (ret) {
dev_err(stmpe->dev, "failed to request IRQ: %d\n", ret);
goto out_removeirq;
@ -951,67 +1026,55 @@ static int __devinit stmpe_probe(struct i2c_client *i2c,
out_removedevs:
mfd_remove_devices(stmpe->dev);
free_irq(stmpe->i2c->irq, stmpe);
free_irq(stmpe->irq, stmpe);
out_removeirq:
stmpe_irq_remove(stmpe);
free_gpio:
if (pdata->irq_over_gpio)
gpio_free(pdata->irq_gpio);
out_free:
kfree(stmpe);
return ret;
}
static int __devexit stmpe_remove(struct i2c_client *client)
int stmpe_remove(struct stmpe *stmpe)
{
struct stmpe *stmpe = i2c_get_clientdata(client);
mfd_remove_devices(stmpe->dev);
free_irq(stmpe->i2c->irq, stmpe);
free_irq(stmpe->irq, stmpe);
stmpe_irq_remove(stmpe);
if (stmpe->pdata->irq_over_gpio)
gpio_free(stmpe->pdata->irq_gpio);
kfree(stmpe);
return 0;
}
static const struct i2c_device_id stmpe_id[] = {
{ "stmpe811", STMPE811 },
{ "stmpe1601", STMPE1601 },
{ "stmpe2401", STMPE2401 },
{ "stmpe2403", STMPE2403 },
{ }
};
MODULE_DEVICE_TABLE(i2c, stmpe_id);
#ifdef CONFIG_PM
static const struct dev_pm_ops stmpe_dev_pm_ops = {
static int stmpe_suspend(struct device *dev)
{
struct stmpe *stmpe = dev_get_drvdata(dev);
if (device_may_wakeup(dev))
enable_irq_wake(stmpe->irq);
return 0;
}
static int stmpe_resume(struct device *dev)
{
struct stmpe *stmpe = dev_get_drvdata(dev);
if (device_may_wakeup(dev))
disable_irq_wake(stmpe->irq);
return 0;
}
const struct dev_pm_ops stmpe_dev_pm_ops = {
.suspend = stmpe_suspend,
.resume = stmpe_resume,
};
#endif
static struct i2c_driver stmpe_driver = {
.driver.name = "stmpe",
.driver.owner = THIS_MODULE,
#ifdef CONFIG_PM
.driver.pm = &stmpe_dev_pm_ops,
#endif
.probe = stmpe_probe,
.remove = __devexit_p(stmpe_remove),
.id_table = stmpe_id,
};
static int __init stmpe_init(void)
{
return i2c_add_driver(&stmpe_driver);
}
subsys_initcall(stmpe_init);
static void __exit stmpe_exit(void)
{
i2c_del_driver(&stmpe_driver);
}
module_exit(stmpe_exit);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("STMPE MFD core driver");
MODULE_AUTHOR("Rabin Vincent <rabin.vincent@stericsson.com>");

View file

@ -8,6 +8,14 @@
#ifndef __STMPE_H
#define __STMPE_H
#include <linux/device.h>
#include <linux/mfd/core.h>
#include <linux/mfd/stmpe.h>
#include <linux/printk.h>
#include <linux/types.h>
extern const struct dev_pm_ops stmpe_dev_pm_ops;
#ifdef STMPE_DUMP_BYTES
static inline void stmpe_dump_bytes(const char *str, const void *buf,
size_t len)
@ -67,10 +75,54 @@ struct stmpe_variant_info {
int (*enable_autosleep)(struct stmpe *stmpe, int autosleep_timeout);
};
/**
* struct stmpe_client_info - i2c or spi specific routines/info
* @data: client specific data
* @read_byte: read single byte
* @write_byte: write single byte
* @read_block: read block or multiple bytes
* @write_block: write block or multiple bytes
* @init: client init routine, called during probe
*/
struct stmpe_client_info {
void *data;
int irq;
void *client;
struct device *dev;
int (*read_byte)(struct stmpe *stmpe, u8 reg);
int (*write_byte)(struct stmpe *stmpe, u8 reg, u8 val);
int (*read_block)(struct stmpe *stmpe, u8 reg, u8 len, u8 *values);
int (*write_block)(struct stmpe *stmpe, u8 reg, u8 len,
const u8 *values);
void (*init)(struct stmpe *stmpe);
};
int stmpe_probe(struct stmpe_client_info *ci, int partnum);
int stmpe_remove(struct stmpe *stmpe);
#define STMPE_ICR_LSB_HIGH (1 << 2)
#define STMPE_ICR_LSB_EDGE (1 << 1)
#define STMPE_ICR_LSB_GIM (1 << 0)
/*
* STMPE801
*/
#define STMPE801_ID 0x0108
#define STMPE801_NR_INTERNAL_IRQS 1
#define STMPE801_REG_CHIP_ID 0x00
#define STMPE801_REG_VERSION_ID 0x02
#define STMPE801_REG_SYS_CTRL 0x04
#define STMPE801_REG_GPIO_INT_EN 0x08
#define STMPE801_REG_GPIO_INT_STA 0x09
#define STMPE801_REG_GPIO_MP_STA 0x10
#define STMPE801_REG_GPIO_SET_PIN 0x11
#define STMPE801_REG_GPIO_DIR 0x12
#define STMPE801_REG_SYS_CTRL_RESET (1 << 7)
#define STMPE801_REG_SYS_CTRL_INT_EN (1 << 2)
#define STMPE801_REG_SYS_CTRL_INT_HI (1 << 0)
/*
* STMPE811
*/
@ -87,6 +139,7 @@ struct stmpe_variant_info {
#define STMPE811_REG_CHIP_ID 0x00
#define STMPE811_REG_SYS_CTRL2 0x04
#define STMPE811_REG_SPI_CFG 0x08
#define STMPE811_REG_INT_CTRL 0x09
#define STMPE811_REG_INT_EN 0x0A
#define STMPE811_REG_INT_STA 0x0B

View file

@ -442,21 +442,7 @@ static struct platform_driver t7l66xb_platform_driver = {
/*--------------------------------------------------------------------------*/
static int __init t7l66xb_init(void)
{
int retval = 0;
retval = platform_driver_register(&t7l66xb_platform_driver);
return retval;
}
static void __exit t7l66xb_exit(void)
{
platform_driver_unregister(&t7l66xb_platform_driver);
}
module_init(t7l66xb_init);
module_exit(t7l66xb_exit);
module_platform_driver(t7l66xb_platform_driver);
MODULE_DESCRIPTION("Toshiba T7L66XB core driver");
MODULE_LICENSE("GPL v2");

View file

@ -234,19 +234,7 @@ static struct platform_driver tc6387xb_platform_driver = {
.resume = tc6387xb_resume,
};
static int __init tc6387xb_init(void)
{
return platform_driver_register(&tc6387xb_platform_driver);
}
static void __exit tc6387xb_exit(void)
{
platform_driver_unregister(&tc6387xb_platform_driver);
}
module_init(tc6387xb_init);
module_exit(tc6387xb_exit);
module_platform_driver(tc6387xb_platform_driver);
MODULE_DESCRIPTION("Toshiba TC6387XB core driver");
MODULE_LICENSE("GPL v2");

View file

@ -458,17 +458,7 @@ static struct platform_driver ti_ssp_driver = {
}
};
static int __init ti_ssp_init(void)
{
return platform_driver_register(&ti_ssp_driver);
}
module_init(ti_ssp_init);
static void __exit ti_ssp_exit(void)
{
platform_driver_unregister(&ti_ssp_driver);
}
module_exit(ti_ssp_exit);
module_platform_driver(ti_ssp_driver);
MODULE_DESCRIPTION("Sequencer Serial Port (SSP) Driver");
MODULE_AUTHOR("Cyril Chemparathy");

View file

@ -857,7 +857,7 @@ static void __devexit timb_remove(struct pci_dev *dev)
kfree(priv);
}
static struct pci_device_id timberdale_pci_tbl[] = {
static DEFINE_PCI_DEVICE_TABLE(timberdale_pci_tbl) = {
{ PCI_DEVICE(PCI_VENDOR_ID_TIMB, PCI_DEVICE_ID_TIMB) },
{ 0 }
};

View file

@ -215,6 +215,7 @@ int tps65910_irq_init(struct tps65910 *tps65910, int irq,
int tps65910_irq_exit(struct tps65910 *tps65910)
{
free_irq(tps65910->chip_irq, tps65910);
if (tps65910->chip_irq)
free_irq(tps65910->chip_irq, tps65910);
return 0;
}

View file

@ -172,15 +172,12 @@ static int tps65910_i2c_probe(struct i2c_client *i2c,
tps65910_gpio_init(tps65910, pmic_plat_data->gpio_base);
ret = tps65910_irq_init(tps65910, init_data->irq, init_data);
if (ret < 0)
goto err;
tps65910_irq_init(tps65910, init_data->irq, init_data);
kfree(init_data);
return ret;
err:
mfd_remove_devices(tps65910->dev);
kfree(tps65910);
kfree(init_data);
return ret;
@ -190,8 +187,8 @@ static int tps65910_i2c_remove(struct i2c_client *i2c)
{
struct tps65910 *tps65910 = i2c_get_clientdata(i2c);
mfd_remove_devices(tps65910->dev);
tps65910_irq_exit(tps65910);
mfd_remove_devices(tps65910->dev);
kfree(tps65910);
return 0;

View file

@ -111,7 +111,6 @@ static int __devexit tps65912_spi_remove(struct spi_device *spi)
static struct spi_driver tps65912_spi_driver = {
.driver = {
.name = "tps65912",
.bus = &spi_bus_type,
.owner = THIS_MODULE,
},
.probe = tps65912_spi_probe,

View file

@ -34,6 +34,11 @@
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/irqdomain.h>
#include <linux/regulator/machine.h>
@ -144,6 +149,9 @@
#define TWL_MODULE_LAST TWL4030_MODULE_LAST
#define TWL4030_NR_IRQS 8
#define TWL6030_NR_IRQS 20
/* Base Address defns for twl4030_map[] */
/* subchip/slave 0 - USB ID */
@ -255,6 +263,7 @@ struct twl_client {
static struct twl_client twl_modules[TWL_NUM_SLAVES];
static struct irq_domain domain;
/* mapping the module id to slave id and base address */
struct twl_mapping {
@ -1183,14 +1192,48 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
int status;
unsigned i;
struct twl4030_platform_data *pdata = client->dev.platform_data;
struct device_node *node = client->dev.of_node;
u8 temp;
int ret = 0;
int nr_irqs = TWL4030_NR_IRQS;
if ((id->driver_data) & TWL6030_CLASS)
nr_irqs = TWL6030_NR_IRQS;
if (node && !pdata) {
/*
* XXX: Temporary pdata until the information is correctly
* retrieved by every TWL modules from DT.
*/
pdata = devm_kzalloc(&client->dev,
sizeof(struct twl4030_platform_data),
GFP_KERNEL);
if (!pdata)
return -ENOMEM;
}
if (!pdata) {
dev_dbg(&client->dev, "no platform data?\n");
return -EINVAL;
}
status = irq_alloc_descs(-1, pdata->irq_base, nr_irqs, 0);
if (IS_ERR_VALUE(status)) {
dev_err(&client->dev, "Fail to allocate IRQ descs\n");
return status;
}
pdata->irq_base = status;
pdata->irq_end = pdata->irq_base + nr_irqs;
domain.irq_base = pdata->irq_base;
domain.nr_irq = nr_irqs;
#ifdef CONFIG_OF_IRQ
domain.of_node = of_node_get(node);
domain.ops = &irq_domain_simple_ops;
#endif
irq_domain_add(&domain);
if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) == 0) {
dev_dbg(&client->dev, "can't talk I2C?\n");
return -EIO;
@ -1270,7 +1313,13 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
twl_i2c_write_u8(TWL4030_MODULE_INTBR, temp, REG_GPPUPDCTR1);
}
status = add_children(pdata, id->driver_data);
#ifdef CONFIG_OF_DEVICE
if (node)
status = of_platform_populate(node, NULL, NULL, &client->dev);
else
#endif
status = add_children(pdata, id->driver_data);
fail:
if (status < 0)
twl_remove(client);

View file

@ -261,17 +261,7 @@ static struct platform_driver twl4030_audio_driver = {
},
};
static int __devinit twl4030_audio_init(void)
{
return platform_driver_register(&twl4030_audio_driver);
}
module_init(twl4030_audio_init);
static void __devexit twl4030_audio_exit(void)
{
platform_driver_unregister(&twl4030_audio_driver);
}
module_exit(twl4030_audio_exit);
module_platform_driver(twl4030_audio_driver);
MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");
MODULE_LICENSE("GPL");

View file

@ -492,7 +492,7 @@ static void twl4030_sih_bus_sync_unlock(struct irq_data *data)
u8 bytes[4];
} imr;
/* byte[0] gets overwriten as we write ... */
/* byte[0] gets overwritten as we write ... */
imr.word = cpu_to_le32(agent->imr << 8);
agent->imr_change_pending = false;
@ -667,6 +667,7 @@ int twl4030_sih_setup(int module)
irq_set_chip_data(irq, agent);
irq_set_chip_and_handler(irq, &twl4030_sih_irq_chip,
handle_edge_irq);
irq_set_nested_thread(irq, 1);
activate_irq(irq);
}

View file

@ -807,19 +807,7 @@ static struct platform_driver twl4030_madc_driver = {
},
};
static int __init twl4030_madc_init(void)
{
return platform_driver_register(&twl4030_madc_driver);
}
module_init(twl4030_madc_init);
static void __exit twl4030_madc_exit(void)
{
platform_driver_unregister(&twl4030_madc_driver);
}
module_exit(twl4030_madc_exit);
module_platform_driver(twl4030_madc_driver);
MODULE_DESCRIPTION("TWL4030 ADC driver");
MODULE_LICENSE("GPL");

View file

@ -34,7 +34,8 @@
static u8 twl4030_start_script_address = 0x2b;
#define PWR_P1_SW_EVENTS 0x10
#define PWR_DEVOFF (1<<0)
#define PWR_DEVOFF (1 << 0)
#define SEQ_OFFSYNC (1 << 0)
#define PHY_TO_OFF_PM_MASTER(p) (p - 0x36)
#define PHY_TO_OFF_PM_RECEIVER(p) (p - 0x5b)
@ -511,12 +512,27 @@ int twl4030_remove_script(u8 flags)
return err;
}
/*
* In master mode, start the power off sequence.
* After a successful execution, TWL shuts down the power to the SoC
* and all peripherals connected to it.
*/
void twl4030_power_off(void)
{
int err;
err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, PWR_DEVOFF,
TWL4030_PM_MASTER_P1_SW_EVENTS);
if (err)
pr_err("TWL4030 Unable to power off\n");
}
void __init twl4030_power_init(struct twl4030_power_data *twl4030_scripts)
{
int err = 0;
int i;
struct twl4030_resconfig *resconfig;
u8 address = twl4030_start_script_address;
u8 val, address = twl4030_start_script_address;
err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER,
TWL4030_PM_MASTER_KEY_CFG1,
@ -548,6 +564,28 @@ void __init twl4030_power_init(struct twl4030_power_data *twl4030_scripts)
}
}
/* Board has to be wired properly to use this feature */
if (twl4030_scripts->use_poweroff && !pm_power_off) {
/* Default for SEQ_OFFSYNC is set, lets ensure this */
err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &val,
TWL4030_PM_MASTER_CFG_P123_TRANSITION);
if (err) {
pr_warning("TWL4030 Unable to read registers\n");
} else if (!(val & SEQ_OFFSYNC)) {
val |= SEQ_OFFSYNC;
err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, val,
TWL4030_PM_MASTER_CFG_P123_TRANSITION);
if (err) {
pr_err("TWL4030 Unable to setup SEQ_OFFSYNC\n");
goto relock;
}
}
pm_power_off = twl4030_power_off;
}
relock:
err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0,
TWL4030_PM_MASTER_PROTECT_KEY);
if (err)

View file

@ -509,13 +509,10 @@ static int __devinit twl6040_probe(struct platform_device *pdev)
twl6040->audpwron = -EINVAL;
if (gpio_is_valid(twl6040->audpwron)) {
ret = gpio_request(twl6040->audpwron, "audpwron");
ret = gpio_request_one(twl6040->audpwron, GPIOF_OUT_INIT_LOW,
"audpwron");
if (ret)
goto gpio1_err;
ret = gpio_direction_output(twl6040->audpwron, 0);
if (ret)
goto gpio2_err;
}
/* codec interrupt */
@ -619,18 +616,7 @@ static struct platform_driver twl6040_driver = {
},
};
static int __devinit twl6040_init(void)
{
return platform_driver_register(&twl6040_driver);
}
module_init(twl6040_init);
static void __devexit twl6040_exit(void)
{
platform_driver_unregister(&twl6040_driver);
}
module_exit(twl6040_exit);
module_platform_driver(twl6040_driver);
MODULE_DESCRIPTION("TWL6040 MFD");
MODULE_AUTHOR("Misael Lopez Cruz <misael.lopez@ti.com>");

View file

@ -36,6 +36,15 @@ static DEFINE_MUTEX(ucb1x00_mutex);
static LIST_HEAD(ucb1x00_drivers);
static LIST_HEAD(ucb1x00_devices);
static struct mcp_device_id ucb1x00_id[] = {
{ "ucb1x00", 0 }, /* auto-detection */
{ "ucb1200", UCB_ID_1200 },
{ "ucb1300", UCB_ID_1300 },
{ "tc35143", UCB_ID_TC35143 },
{ }
};
MODULE_DEVICE_TABLE(mcp, ucb1x00_id);
/**
* ucb1x00_io_set_dir - set IO direction
* @ucb: UCB1x00 structure describing chip
@ -527,17 +536,33 @@ static struct class ucb1x00_class = {
static int ucb1x00_probe(struct mcp *mcp)
{
const struct mcp_device_id *mid;
struct ucb1x00 *ucb;
struct ucb1x00_driver *drv;
struct ucb1x00_plat_data *pdata;
unsigned int id;
int ret = -ENODEV;
int temp;
mcp_enable(mcp);
id = mcp_reg_read(mcp, UCB_ID);
mid = mcp_get_device_id(mcp);
if (id != UCB_ID_1200 && id != UCB_ID_1300 && id != UCB_ID_TC35143) {
printk(KERN_WARNING "UCB1x00 ID not found: %04x\n", id);
if (mid && mid->driver_data) {
if (id != mid->driver_data) {
printk(KERN_WARNING "%s wrong ID %04x found: %04x\n",
mid->name, (unsigned int) mid->driver_data, id);
goto err_disable;
}
} else {
mid = &ucb1x00_id[1];
while (mid->driver_data) {
if (id == mid->driver_data)
break;
mid++;
}
printk(KERN_WARNING "%s ID not found: %04x\n",
ucb1x00_id[0].name, id);
goto err_disable;
}
@ -546,28 +571,28 @@ static int ucb1x00_probe(struct mcp *mcp)
if (!ucb)
goto err_disable;
pdata = mcp->attached_device.platform_data;
ucb->dev.class = &ucb1x00_class;
ucb->dev.parent = &mcp->attached_device;
dev_set_name(&ucb->dev, "ucb1x00");
dev_set_name(&ucb->dev, mid->name);
spin_lock_init(&ucb->lock);
spin_lock_init(&ucb->io_lock);
sema_init(&ucb->adc_sem, 1);
ucb->id = id;
ucb->id = mid;
ucb->mcp = mcp;
ucb->irq = ucb1x00_detect_irq(ucb);
if (ucb->irq == NO_IRQ) {
printk(KERN_ERR "UCB1x00: IRQ probe failed\n");
printk(KERN_ERR "%s: IRQ probe failed\n", mid->name);
ret = -ENODEV;
goto err_free;
}
ucb->gpio.base = -1;
if (mcp->gpio_base != 0) {
if (pdata && (pdata->gpio_base >= 0)) {
ucb->gpio.label = dev_name(&ucb->dev);
ucb->gpio.base = mcp->gpio_base;
ucb->gpio.base = pdata->gpio_base;
ucb->gpio.ngpio = 10;
ucb->gpio.set = ucb1x00_gpio_set;
ucb->gpio.get = ucb1x00_gpio_get;
@ -580,10 +605,10 @@ static int ucb1x00_probe(struct mcp *mcp)
dev_info(&ucb->dev, "gpio_base not set so no gpiolib support");
ret = request_irq(ucb->irq, ucb1x00_irq, IRQF_TRIGGER_RISING,
"UCB1x00", ucb);
mid->name, ucb);
if (ret) {
printk(KERN_ERR "ucb1x00: unable to grab irq%d: %d\n",
ucb->irq, ret);
printk(KERN_ERR "%s: unable to grab irq%d: %d\n",
mid->name, ucb->irq, ret);
goto err_gpio;
}
@ -705,6 +730,7 @@ static struct mcp_driver ucb1x00_driver = {
.remove = ucb1x00_remove,
.suspend = ucb1x00_suspend,
.resume = ucb1x00_resume,
.id_table = ucb1x00_id,
};
static int __init ucb1x00_init(void)

View file

@ -382,7 +382,7 @@ static int ucb1x00_ts_add(struct ucb1x00_dev *dev)
ts->adcsync = adcsync ? UCB_SYNC : UCB_NOSYNC;
idev->name = "Touchscreen panel";
idev->id.product = ts->ucb->id;
idev->id.product = ts->ucb->id->driver_data;
idev->open = ucb1x00_ts_open;
idev->close = ucb1x00_ts_close;

View file

@ -118,7 +118,7 @@ static void __devexit vx855_remove(struct pci_dev *pdev)
pci_disable_device(pdev);
}
static struct pci_device_id vx855_pci_tbl[] = {
static DEFINE_PCI_DEVICE_TABLE(vx855_pci_tbl) = {
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX855) },
{ 0, }
};

View file

@ -559,6 +559,8 @@ static int wm831x_write(struct wm831x *wm831x, unsigned short reg,
dev_vdbg(wm831x->dev, "Write %04x to R%d(0x%x)\n",
buf[i], reg + i, reg + i);
ret = regmap_write(wm831x->regmap, reg + i, buf[i]);
if (ret != 0)
return ret;
}
return 0;
@ -1875,7 +1877,6 @@ err_irq:
err_regmap:
mfd_remove_devices(wm831x->dev);
regmap_exit(wm831x->regmap);
kfree(wm831x);
return ret;
}
@ -1887,7 +1888,6 @@ void wm831x_device_exit(struct wm831x *wm831x)
free_irq(wm831x->irq_base + WM831X_IRQ_AUXADC_DATA, wm831x);
wm831x_irq_exit(wm831x);
regmap_exit(wm831x->regmap);
kfree(wm831x);
}
int wm831x_device_suspend(struct wm831x *wm831x)

View file

@ -30,7 +30,7 @@ static int wm831x_i2c_probe(struct i2c_client *i2c,
struct wm831x *wm831x;
int ret;
wm831x = kzalloc(sizeof(struct wm831x), GFP_KERNEL);
wm831x = devm_kzalloc(&i2c->dev, sizeof(struct wm831x), GFP_KERNEL);
if (wm831x == NULL)
return -ENOMEM;
@ -42,7 +42,6 @@ static int wm831x_i2c_probe(struct i2c_client *i2c,
ret = PTR_ERR(wm831x->regmap);
dev_err(wm831x->dev, "Failed to allocate register map: %d\n",
ret);
kfree(wm831x);
return ret;
}

View file

@ -325,11 +325,6 @@ static inline int irq_data_to_status_reg(struct wm831x_irq_data *irq_data)
return WM831X_INTERRUPT_STATUS_1 - 1 + irq_data->reg;
}
static inline int irq_data_to_mask_reg(struct wm831x_irq_data *irq_data)
{
return WM831X_INTERRUPT_STATUS_1_MASK - 1 + irq_data->reg;
}
static inline struct wm831x_irq_data *irq_to_wm831x_irq(struct wm831x *wm831x,
int irq)
{
@ -477,8 +472,7 @@ static irqreturn_t wm831x_irq_thread(int irq, void *data)
handle_nested_irq(wm831x->irq_base + WM831X_IRQ_TCHPD);
if (primary & WM831X_TCHDATA_INT)
handle_nested_irq(wm831x->irq_base + WM831X_IRQ_TCHDATA);
if (primary & (WM831X_TCHDATA_EINT | WM831X_TCHPD_EINT))
goto out;
primary &= ~(WM831X_TCHDATA_EINT | WM831X_TCHPD_EINT);
for (i = 0; i < ARRAY_SIZE(wm831x_irqs); i++) {
int offset = wm831x_irqs[i].reg - 1;

View file

@ -30,7 +30,7 @@ static int __devinit wm831x_spi_probe(struct spi_device *spi)
type = (enum wm831x_parent)id->driver_data;
wm831x = kzalloc(sizeof(struct wm831x), GFP_KERNEL);
wm831x = devm_kzalloc(&spi->dev, sizeof(struct wm831x), GFP_KERNEL);
if (wm831x == NULL)
return -ENOMEM;
@ -45,7 +45,6 @@ static int __devinit wm831x_spi_probe(struct spi_device *spi)
ret = PTR_ERR(wm831x->regmap);
dev_err(wm831x->dev, "Failed to allocate register map: %d\n",
ret);
kfree(wm831x);
return ret;
}
@ -95,7 +94,6 @@ MODULE_DEVICE_TABLE(spi, wm831x_spi_id);
static struct spi_driver wm831x_spi_driver = {
.driver = {
.name = "wm831x",
.bus = &spi_bus_type,
.owner = THIS_MODULE,
.pm = &wm831x_spi_pm,
},

View file

@ -573,6 +573,8 @@ int wm8350_device_init(struct wm8350 *wm8350, int irq,
u16 id1, id2, mask_rev;
u16 cust_id, mode, chip_rev;
dev_set_drvdata(wm8350->dev, wm8350);
/* get WM8350 revision and config mode */
ret = wm8350->read_dev(wm8350, WM8350_RESET_ID, sizeof(id1), &id1);
if (ret != 0) {

View file

@ -63,7 +63,7 @@ static int wm8350_i2c_probe(struct i2c_client *i2c,
struct wm8350 *wm8350;
int ret = 0;
wm8350 = kzalloc(sizeof(struct wm8350), GFP_KERNEL);
wm8350 = devm_kzalloc(&i2c->dev, sizeof(struct wm8350), GFP_KERNEL);
if (wm8350 == NULL)
return -ENOMEM;
@ -80,7 +80,6 @@ static int wm8350_i2c_probe(struct i2c_client *i2c,
return ret;
err:
kfree(wm8350);
return ret;
}
@ -89,7 +88,6 @@ static int wm8350_i2c_remove(struct i2c_client *i2c)
struct wm8350 *wm8350 = i2c_get_clientdata(i2c);
wm8350_device_exit(wm8350);
kfree(wm8350);
return 0;
}

View file

@ -344,7 +344,7 @@ static int wm8400_i2c_probe(struct i2c_client *i2c,
struct wm8400 *wm8400;
int ret;
wm8400 = kzalloc(sizeof(struct wm8400), GFP_KERNEL);
wm8400 = devm_kzalloc(&i2c->dev, sizeof(struct wm8400), GFP_KERNEL);
if (wm8400 == NULL) {
ret = -ENOMEM;
goto err;
@ -353,7 +353,7 @@ static int wm8400_i2c_probe(struct i2c_client *i2c,
wm8400->regmap = regmap_init_i2c(i2c, &wm8400_regmap_config);
if (IS_ERR(wm8400->regmap)) {
ret = PTR_ERR(wm8400->regmap);
goto struct_err;
goto err;
}
wm8400->dev = &i2c->dev;
@ -367,8 +367,6 @@ static int wm8400_i2c_probe(struct i2c_client *i2c,
map_err:
regmap_exit(wm8400->regmap);
struct_err:
kfree(wm8400);
err:
return ret;
}
@ -379,7 +377,6 @@ static int wm8400_i2c_remove(struct i2c_client *i2c)
wm8400_release(wm8400);
regmap_exit(wm8400->regmap);
kfree(wm8400);
return 0;
}

View file

@ -500,6 +500,14 @@ config USB_SWITCH_FSA9480
stereo and mono audio, video, microphone and UART data to use
a common connector port.
config MAX8997_MUIC
tristate "MAX8997 MUIC Support"
depends on MFD_MAX8997
help
If you say yes here you get support for the MUIC device of
Maxim MAX8997 PMIC.
The MAX8997 MUIC is a USB port accessory detector and switch.
source "drivers/misc/c2port/Kconfig"
source "drivers/misc/eeprom/Kconfig"
source "drivers/misc/cb710/Kconfig"

View file

@ -48,3 +48,4 @@ obj-y += lis3lv02d/
obj-y += carma/
obj-$(CONFIG_USB_SWITCH_FSA9480) += fsa9480.o
obj-$(CONFIG_ALTERA_STAPL) +=altera-stapl/
obj-$(CONFIG_MAX8997_MUIC) += max8997-muic.o

View file

@ -8,8 +8,8 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/pwm.h>
#include <linux/mfd/ab8500.h>
#include <linux/mfd/abx500.h>
#include <linux/mfd/abx500/ab8500.h>
#include <linux/module.h>
/*

505
drivers/misc/max8997-muic.c Normal file
View file

@ -0,0 +1,505 @@
/*
* max8997-muic.c - MAX8997 muic driver for the Maxim 8997
*
* Copyright (C) 2011 Samsung Electrnoics
* Donggeun Kim <dg77.kim@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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/kernel.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/kobject.h>
#include <linux/mfd/max8997.h>
#include <linux/mfd/max8997-private.h>
/* MAX8997-MUIC STATUS1 register */
#define STATUS1_ADC_SHIFT 0
#define STATUS1_ADCLOW_SHIFT 5
#define STATUS1_ADCERR_SHIFT 6
#define STATUS1_ADC_MASK (0x1f << STATUS1_ADC_SHIFT)
#define STATUS1_ADCLOW_MASK (0x1 << STATUS1_ADCLOW_SHIFT)
#define STATUS1_ADCERR_MASK (0x1 << STATUS1_ADCERR_SHIFT)
/* MAX8997-MUIC STATUS2 register */
#define STATUS2_CHGTYP_SHIFT 0
#define STATUS2_CHGDETRUN_SHIFT 3
#define STATUS2_DCDTMR_SHIFT 4
#define STATUS2_DBCHG_SHIFT 5
#define STATUS2_VBVOLT_SHIFT 6
#define STATUS2_CHGTYP_MASK (0x7 << STATUS2_CHGTYP_SHIFT)
#define STATUS2_CHGDETRUN_MASK (0x1 << STATUS2_CHGDETRUN_SHIFT)
#define STATUS2_DCDTMR_MASK (0x1 << STATUS2_DCDTMR_SHIFT)
#define STATUS2_DBCHG_MASK (0x1 << STATUS2_DBCHG_SHIFT)
#define STATUS2_VBVOLT_MASK (0x1 << STATUS2_VBVOLT_SHIFT)
/* MAX8997-MUIC STATUS3 register */
#define STATUS3_OVP_SHIFT 2
#define STATUS3_OVP_MASK (0x1 << STATUS3_OVP_SHIFT)
/* MAX8997-MUIC CONTROL1 register */
#define COMN1SW_SHIFT 0
#define COMP2SW_SHIFT 3
#define COMN1SW_MASK (0x7 << COMN1SW_SHIFT)
#define COMP2SW_MASK (0x7 << COMP2SW_SHIFT)
#define SW_MASK (COMP2SW_MASK | COMN1SW_MASK)
#define MAX8997_SW_USB ((1 << COMP2SW_SHIFT) | (1 << COMN1SW_SHIFT))
#define MAX8997_SW_AUDIO ((2 << COMP2SW_SHIFT) | (2 << COMN1SW_SHIFT))
#define MAX8997_SW_UART ((3 << COMP2SW_SHIFT) | (3 << COMN1SW_SHIFT))
#define MAX8997_SW_OPEN ((0 << COMP2SW_SHIFT) | (0 << COMN1SW_SHIFT))
#define MAX8997_ADC_GROUND 0x00
#define MAX8997_ADC_MHL 0x01
#define MAX8997_ADC_JIG_USB_1 0x18
#define MAX8997_ADC_JIG_USB_2 0x19
#define MAX8997_ADC_DESKDOCK 0x1a
#define MAX8997_ADC_JIG_UART 0x1c
#define MAX8997_ADC_CARDOCK 0x1d
#define MAX8997_ADC_OPEN 0x1f
struct max8997_muic_irq {
unsigned int irq;
const char *name;
};
static struct max8997_muic_irq muic_irqs[] = {
{ MAX8997_MUICIRQ_ADCError, "muic-ADC_error" },
{ MAX8997_MUICIRQ_ADCLow, "muic-ADC_low" },
{ MAX8997_MUICIRQ_ADC, "muic-ADC" },
{ MAX8997_MUICIRQ_VBVolt, "muic-VB_voltage" },
{ MAX8997_MUICIRQ_DBChg, "muic-DB_charger" },
{ MAX8997_MUICIRQ_DCDTmr, "muic-DCD_timer" },
{ MAX8997_MUICIRQ_ChgDetRun, "muic-CDR_status" },
{ MAX8997_MUICIRQ_ChgTyp, "muic-charger_type" },
{ MAX8997_MUICIRQ_OVP, "muic-over_voltage" },
};
struct max8997_muic_info {
struct device *dev;
struct max8997_dev *iodev;
struct i2c_client *muic;
struct max8997_muic_platform_data *muic_pdata;
int irq;
struct work_struct irq_work;
enum max8997_muic_charger_type pre_charger_type;
int pre_adc;
struct mutex mutex;
};
static int max8997_muic_handle_usb(struct max8997_muic_info *info,
enum max8997_muic_usb_type usb_type, bool attached)
{
struct max8997_muic_platform_data *mdata = info->muic_pdata;
int ret = 0;
if (usb_type == MAX8997_USB_HOST) {
/* switch to USB */
ret = max8997_update_reg(info->muic, MAX8997_MUIC_REG_CONTROL1,
attached ? MAX8997_SW_USB : MAX8997_SW_OPEN,
SW_MASK);
if (ret) {
dev_err(info->dev, "failed to update muic register\n");
goto out;
}
}
if (mdata->usb_callback)
mdata->usb_callback(usb_type, attached);
out:
return ret;
}
static void max8997_muic_handle_mhl(struct max8997_muic_info *info,
bool attached)
{
struct max8997_muic_platform_data *mdata = info->muic_pdata;
if (mdata->mhl_callback)
mdata->mhl_callback(attached);
}
static int max8997_muic_handle_dock(struct max8997_muic_info *info,
int adc, bool attached)
{
struct max8997_muic_platform_data *mdata = info->muic_pdata;
int ret = 0;
/* switch to AUDIO */
ret = max8997_update_reg(info->muic, MAX8997_MUIC_REG_CONTROL1,
attached ? MAX8997_SW_AUDIO : MAX8997_SW_OPEN,
SW_MASK);
if (ret) {
dev_err(info->dev, "failed to update muic register\n");
goto out;
}
switch (adc) {
case MAX8997_ADC_DESKDOCK:
if (mdata->deskdock_callback)
mdata->deskdock_callback(attached);
break;
case MAX8997_ADC_CARDOCK:
if (mdata->cardock_callback)
mdata->cardock_callback(attached);
break;
default:
break;
}
out:
return ret;
}
static int max8997_muic_handle_jig_uart(struct max8997_muic_info *info,
bool attached)
{
struct max8997_muic_platform_data *mdata = info->muic_pdata;
int ret = 0;
/* switch to UART */
ret = max8997_update_reg(info->muic, MAX8997_MUIC_REG_CONTROL1,
attached ? MAX8997_SW_UART : MAX8997_SW_OPEN,
SW_MASK);
if (ret) {
dev_err(info->dev, "failed to update muic register\n");
goto out;
}
if (mdata->uart_callback)
mdata->uart_callback(attached);
out:
return ret;
}
static int max8997_muic_handle_adc_detach(struct max8997_muic_info *info)
{
int ret = 0;
switch (info->pre_adc) {
case MAX8997_ADC_GROUND:
ret = max8997_muic_handle_usb(info, MAX8997_USB_HOST, false);
break;
case MAX8997_ADC_MHL:
max8997_muic_handle_mhl(info, false);
break;
case MAX8997_ADC_JIG_USB_1:
case MAX8997_ADC_JIG_USB_2:
ret = max8997_muic_handle_usb(info, MAX8997_USB_DEVICE, false);
break;
case MAX8997_ADC_DESKDOCK:
case MAX8997_ADC_CARDOCK:
ret = max8997_muic_handle_dock(info, info->pre_adc, false);
break;
case MAX8997_ADC_JIG_UART:
ret = max8997_muic_handle_jig_uart(info, false);
break;
default:
break;
}
return ret;
}
static int max8997_muic_handle_adc(struct max8997_muic_info *info, int adc)
{
int ret = 0;
switch (adc) {
case MAX8997_ADC_GROUND:
ret = max8997_muic_handle_usb(info, MAX8997_USB_HOST, true);
break;
case MAX8997_ADC_MHL:
max8997_muic_handle_mhl(info, true);
break;
case MAX8997_ADC_JIG_USB_1:
case MAX8997_ADC_JIG_USB_2:
ret = max8997_muic_handle_usb(info, MAX8997_USB_DEVICE, true);
break;
case MAX8997_ADC_DESKDOCK:
case MAX8997_ADC_CARDOCK:
ret = max8997_muic_handle_dock(info, adc, true);
break;
case MAX8997_ADC_JIG_UART:
ret = max8997_muic_handle_jig_uart(info, true);
break;
case MAX8997_ADC_OPEN:
ret = max8997_muic_handle_adc_detach(info);
break;
default:
break;
}
info->pre_adc = adc;
return ret;
}
static int max8997_muic_handle_charger_type(struct max8997_muic_info *info,
enum max8997_muic_charger_type charger_type)
{
struct max8997_muic_platform_data *mdata = info->muic_pdata;
u8 adc;
int ret;
ret = max8997_read_reg(info->muic, MAX8997_MUIC_REG_STATUS1, &adc);
if (ret) {
dev_err(info->dev, "failed to read muic register\n");
goto out;
}
switch (charger_type) {
case MAX8997_CHARGER_TYPE_NONE:
if (mdata->charger_callback)
mdata->charger_callback(false, charger_type);
if (info->pre_charger_type == MAX8997_CHARGER_TYPE_USB) {
max8997_muic_handle_usb(info,
MAX8997_USB_DEVICE, false);
}
break;
case MAX8997_CHARGER_TYPE_USB:
if ((adc & STATUS1_ADC_MASK) == MAX8997_ADC_OPEN) {
max8997_muic_handle_usb(info,
MAX8997_USB_DEVICE, true);
}
if (mdata->charger_callback)
mdata->charger_callback(true, charger_type);
break;
case MAX8997_CHARGER_TYPE_DOWNSTREAM_PORT:
case MAX8997_CHARGER_TYPE_DEDICATED_CHG:
case MAX8997_CHARGER_TYPE_500MA:
case MAX8997_CHARGER_TYPE_1A:
if (mdata->charger_callback)
mdata->charger_callback(true, charger_type);
break;
default:
break;
}
info->pre_charger_type = charger_type;
out:
return ret;
}
static void max8997_muic_irq_work(struct work_struct *work)
{
struct max8997_muic_info *info = container_of(work,
struct max8997_muic_info, irq_work);
struct max8997_platform_data *pdata =
dev_get_platdata(info->iodev->dev);
u8 status[3];
u8 adc, chg_type;
int irq_type = info->irq - pdata->irq_base;
int ret;
mutex_lock(&info->mutex);
ret = max8997_bulk_read(info->muic, MAX8997_MUIC_REG_STATUS1,
3, status);
if (ret) {
dev_err(info->dev, "failed to read muic register\n");
mutex_unlock(&info->mutex);
return;
}
dev_dbg(info->dev, "%s: STATUS1:0x%x, 2:0x%x\n", __func__,
status[0], status[1]);
switch (irq_type) {
case MAX8997_MUICIRQ_ADC:
adc = status[0] & STATUS1_ADC_MASK;
adc >>= STATUS1_ADC_SHIFT;
max8997_muic_handle_adc(info, adc);
break;
case MAX8997_MUICIRQ_ChgTyp:
chg_type = status[1] & STATUS2_CHGTYP_MASK;
chg_type >>= STATUS2_CHGTYP_SHIFT;
max8997_muic_handle_charger_type(info, chg_type);
break;
default:
dev_info(info->dev, "misc interrupt: %s occurred\n",
muic_irqs[irq_type].name);
break;
}
mutex_unlock(&info->mutex);
return;
}
static irqreturn_t max8997_muic_irq_handler(int irq, void *data)
{
struct max8997_muic_info *info = data;
dev_dbg(info->dev, "irq:%d\n", irq);
info->irq = irq;
schedule_work(&info->irq_work);
return IRQ_HANDLED;
}
static void max8997_muic_detect_dev(struct max8997_muic_info *info)
{
int ret;
u8 status[2], adc, chg_type;
ret = max8997_bulk_read(info->muic, MAX8997_MUIC_REG_STATUS1,
2, status);
if (ret) {
dev_err(info->dev, "failed to read muic register\n");
return;
}
dev_info(info->dev, "STATUS1:0x%x, STATUS2:0x%x\n",
status[0], status[1]);
adc = status[0] & STATUS1_ADC_MASK;
adc >>= STATUS1_ADC_SHIFT;
chg_type = status[1] & STATUS2_CHGTYP_MASK;
chg_type >>= STATUS2_CHGTYP_SHIFT;
max8997_muic_handle_adc(info, adc);
max8997_muic_handle_charger_type(info, chg_type);
}
static void max8997_initialize_device(struct max8997_muic_info *info)
{
struct max8997_muic_platform_data *mdata = info->muic_pdata;
int i;
for (i = 0; i < mdata->num_init_data; i++) {
max8997_write_reg(info->muic, mdata->init_data[i].addr,
mdata->init_data[i].data);
}
}
static int __devinit max8997_muic_probe(struct platform_device *pdev)
{
struct max8997_dev *iodev = dev_get_drvdata(pdev->dev.parent);
struct max8997_platform_data *pdata = dev_get_platdata(iodev->dev);
struct max8997_muic_info *info;
int ret, i;
info = kzalloc(sizeof(struct max8997_muic_info), GFP_KERNEL);
if (!info) {
dev_err(&pdev->dev, "failed to allocate memory\n");
ret = -ENOMEM;
goto err_kfree;
}
if (!pdata->muic_pdata) {
dev_err(&pdev->dev, "failed to get platform_data\n");
ret = -EINVAL;
goto err_pdata;
}
info->muic_pdata = pdata->muic_pdata;
info->dev = &pdev->dev;
info->iodev = iodev;
info->muic = iodev->muic;
platform_set_drvdata(pdev, info);
mutex_init(&info->mutex);
INIT_WORK(&info->irq_work, max8997_muic_irq_work);
for (i = 0; i < ARRAY_SIZE(muic_irqs); i++) {
struct max8997_muic_irq *muic_irq = &muic_irqs[i];
ret = request_threaded_irq(pdata->irq_base + muic_irq->irq,
NULL, max8997_muic_irq_handler,
0, muic_irq->name,
info);
if (ret) {
dev_err(&pdev->dev,
"failed: irq request (IRQ: %d,"
" error :%d)\n",
muic_irq->irq, ret);
for (i = i - 1; i >= 0; i--)
free_irq(muic_irq->irq, info);
goto err_irq;
}
}
/* Initialize registers according to platform data */
max8997_initialize_device(info);
/* Initial device detection */
max8997_muic_detect_dev(info);
return ret;
err_irq:
err_pdata:
kfree(info);
err_kfree:
return ret;
}
static int __devexit max8997_muic_remove(struct platform_device *pdev)
{
struct max8997_muic_info *info = platform_get_drvdata(pdev);
struct max8997_platform_data *pdata =
dev_get_platdata(info->iodev->dev);
int i;
for (i = 0; i < ARRAY_SIZE(muic_irqs); i++)
free_irq(pdata->irq_base + muic_irqs[i].irq, info);
cancel_work_sync(&info->irq_work);
kfree(info);
return 0;
}
static struct platform_driver max8997_muic_driver = {
.driver = {
.name = "max8997-muic",
.owner = THIS_MODULE,
},
.probe = max8997_muic_probe,
.remove = __devexit_p(max8997_muic_remove),
};
static int __init max8997_muic_init(void)
{
return platform_driver_register(&max8997_muic_driver);
}
module_init(max8997_muic_init);
static void __exit max8997_muic_exit(void)
{
platform_driver_unregister(&max8997_muic_driver);
}
module_exit(max8997_muic_exit);
MODULE_DESCRIPTION("Maxim MAX8997 MUIC driver");
MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>");
MODULE_LICENSE("GPL");

View file

@ -16,8 +16,8 @@
#include <linux/module.h>
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/mfd/ab8500.h>
#include <linux/mfd/abx500.h>
#include <linux/mfd/abx500/ab8500.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/ab8500.h>

View file

@ -15,7 +15,7 @@
#include <linux/platform_device.h>
#include <linux/rtc.h>
#include <linux/mfd/abx500.h>
#include <linux/mfd/ab8500.h>
#include <linux/mfd/abx500/ab8500.h>
#include <linux/delay.h>
#define AB8500_RTC_SOFF_STAT_REG 0x00

View file

@ -261,6 +261,8 @@ static int __devinit max8925_rtc_probe(struct platform_device *pdev)
/* XXX - isn't this redundant? */
platform_set_drvdata(pdev, info);
device_init_wakeup(&pdev->dev, 1);
info->rtc_dev = rtc_device_register("max8925-rtc", &pdev->dev,
&max8925_rtc_ops, THIS_MODULE);
ret = PTR_ERR(info->rtc_dev);
@ -290,10 +292,34 @@ static int __devexit max8925_rtc_remove(struct platform_device *pdev)
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int max8925_rtc_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);
if (device_may_wakeup(dev))
chip->wakeup_flag |= 1 << MAX8925_IRQ_RTC_ALARM0;
return 0;
}
static int max8925_rtc_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);
if (device_may_wakeup(dev))
chip->wakeup_flag &= ~(1 << MAX8925_IRQ_RTC_ALARM0);
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(max8925_rtc_pm_ops, max8925_rtc_suspend, max8925_rtc_resume);
static struct platform_driver max8925_rtc_driver = {
.driver = {
.name = "max8925-rtc",
.owner = THIS_MODULE,
.pm = &max8925_rtc_pm_ops,
},
.probe = max8925_rtc_probe,
.remove = __devexit_p(max8925_rtc_remove),

View file

@ -30,7 +30,7 @@
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/mfd/abx500.h>
#include <linux/mfd/ab8500.h>
#include <linux/mfd/abx500/ab8500.h>
#define AB8500_MAIN_WD_CTRL_REG 0x01
#define AB8500_USB_LINE_STAT_REG 0x80

View file

@ -652,10 +652,12 @@ struct twl4030_power_data {
unsigned num;
struct twl4030_resconfig *resource_config;
#define TWL4030_RESCONFIG_UNDEF ((u8)-1)
bool use_poweroff; /* Board is wired for TWL poweroff */
};
extern void twl4030_power_init(struct twl4030_power_data *triton2_scripts);
extern int twl4030_remove_script(u8 flags);
extern void twl4030_power_off(void);
struct twl4030_codec_data {
unsigned int digimic_delay; /* in ms */

View file

@ -297,10 +297,11 @@ enum {
struct pm860x_chip {
struct device *dev;
struct mutex io_lock;
struct mutex irq_lock;
struct i2c_client *client;
struct i2c_client *companion; /* companion chip client */
struct regmap *regmap;
struct regmap *regmap_companion;
int buck3_double; /* DVC ramp slope double */
unsigned short companion_addr;

View file

@ -203,6 +203,8 @@ struct max8925_chip {
int irq_base;
int core_irq;
int tsc_irq;
unsigned int wakeup_flag;
};
struct max8925_backlight_pdata {

View file

@ -77,6 +77,82 @@ struct max8997_regulator_data {
struct regulator_init_data *initdata;
};
enum max8997_muic_usb_type {
MAX8997_USB_HOST,
MAX8997_USB_DEVICE,
};
enum max8997_muic_charger_type {
MAX8997_CHARGER_TYPE_NONE = 0,
MAX8997_CHARGER_TYPE_USB,
MAX8997_CHARGER_TYPE_DOWNSTREAM_PORT,
MAX8997_CHARGER_TYPE_DEDICATED_CHG,
MAX8997_CHARGER_TYPE_500MA,
MAX8997_CHARGER_TYPE_1A,
MAX8997_CHARGER_TYPE_DEAD_BATTERY = 7,
};
struct max8997_muic_reg_data {
u8 addr;
u8 data;
};
/**
* struct max8997_muic_platform_data
* @usb_callback: callback function for USB
* inform callee of USB type (HOST or DEVICE)
* and attached state(true or false)
* @charger_callback: callback function for charger
* inform callee of charger_type
* and attached state(true or false)
* @deskdock_callback: callback function for desk dock
* inform callee of attached state(true or false)
* @cardock_callback: callback function for car dock
* inform callee of attached state(true or false)
* @mhl_callback: callback function for MHL (Mobile High-definition Link)
* inform callee of attached state(true or false)
* @uart_callback: callback function for JIG UART
* inform callee of attached state(true or false)
* @init_data: array of max8997_muic_reg_data
* used for initializing registers of MAX8997 MUIC device
* @num_init_data: array size of init_data
*/
struct max8997_muic_platform_data {
void (*usb_callback)(enum max8997_muic_usb_type usb_type,
bool attached);
void (*charger_callback)(bool attached,
enum max8997_muic_charger_type charger_type);
void (*deskdock_callback) (bool attached);
void (*cardock_callback) (bool attached);
void (*mhl_callback) (bool attached);
void (*uart_callback) (bool attached);
struct max8997_muic_reg_data *init_data;
int num_init_data;
};
enum max8997_led_mode {
MAX8997_NONE,
MAX8997_FLASH_MODE,
MAX8997_MOVIE_MODE,
MAX8997_FLASH_PIN_CONTROL_MODE,
MAX8997_MOVIE_PIN_CONTROL_MODE,
};
/**
* struct max8997_led_platform_data
* The number of LED devices for MAX8997 is two
* @mode: LED mode for each LED device
* @brightness: initial brightness for each LED device
* range:
* [0 - 31]: MAX8997_FLASH_MODE and MAX8997_FLASH_PIN_CONTROL_MODE
* [0 - 15]: MAX8997_MOVIE_MODE and MAX8997_MOVIE_PIN_CONTROL_MODE
*/
struct max8997_led_platform_data {
enum max8997_led_mode mode[2];
u8 brightness[2];
};
struct max8997_platform_data {
/* IRQ */
int irq_base;
@ -113,10 +189,13 @@ struct max8997_platform_data {
/* charge Full Timeout */
int timeout; /* 0 (no timeout), 5, 6, 7 hours */
/* MUIC: Not implemented */
/* ---- MUIC ---- */
struct max8997_muic_platform_data *muic_pdata;
/* HAPTIC: Not implemented */
/* RTC: Not implemented */
/* Flash: Not implemented */
/* ---- LED ---- */
struct max8997_led_platform_data *led_pdata;
};
#endif /* __LINUX_MFD_MAX8998_H */

View file

@ -174,6 +174,9 @@ struct mc13xxx_platform_data {
#define MC13XXX_ADC_MODE_MULT_CHAN 3
#define MC13XXX_ADC0 43
#define MC13XXX_ADC0_LICELLCON (1 << 0)
#define MC13XXX_ADC0_CHRGICON (1 << 1)
#define MC13XXX_ADC0_BATICON (1 << 2)
#define MC13XXX_ADC0_ADREFEN (1 << 10)
#define MC13XXX_ADC0_TSMOD0 (1 << 12)
#define MC13XXX_ADC0_TSMOD1 (1 << 13)
@ -185,4 +188,9 @@ struct mc13xxx_platform_data {
MC13XXX_ADC0_TSMOD1 | \
MC13XXX_ADC0_TSMOD2)
#define MC13XXX_ADC0_CONFIG_MASK (MC13XXX_ADC0_TSMOD_MASK | \
MC13XXX_ADC0_LICELLCON | \
MC13XXX_ADC0_CHRGICON | \
MC13XXX_ADC0_BATICON)
#endif /* ifndef __LINUX_MFD_MC13XXX_H */

View file

@ -10,6 +10,7 @@
#ifndef MCP_H
#define MCP_H
#include <linux/mod_devicetable.h>
#include <mach/dma.h>
struct mcp_ops;
@ -26,7 +27,7 @@ struct mcp {
dma_device_t dma_telco_rd;
dma_device_t dma_telco_wr;
struct device attached_device;
int gpio_base;
const char *codec;
};
struct mcp_ops {
@ -44,10 +45,11 @@ void mcp_reg_write(struct mcp *, unsigned int, unsigned int);
unsigned int mcp_reg_read(struct mcp *, unsigned int);
void mcp_enable(struct mcp *);
void mcp_disable(struct mcp *);
const struct mcp_device_id *mcp_get_device_id(const struct mcp *mcp);
#define mcp_get_sclk_rate(mcp) ((mcp)->sclk_rate)
struct mcp *mcp_host_alloc(struct device *, size_t);
int mcp_host_register(struct mcp *);
int mcp_host_register(struct mcp *, void *);
void mcp_host_unregister(struct mcp *);
struct mcp_driver {
@ -56,6 +58,7 @@ struct mcp_driver {
void (*remove)(struct mcp *);
int (*suspend)(struct mcp *, pm_message_t);
int (*resume)(struct mcp *);
const struct mcp_device_id *id_table;
};
int mcp_driver_register(struct mcp_driver *);

View file

@ -0,0 +1,373 @@
/*
* s5m-core.h
*
* Copyright (c) 2011 Samsung Electronics Co., Ltd
* http://www.samsung.com
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
*/
#ifndef __LINUX_MFD_S5M_CORE_H
#define __LINUX_MFD_S5M_CORE_H
#define NUM_IRQ_REGS 4
enum s5m_device_type {
S5M8751X,
S5M8763X,
S5M8767X,
};
/* S5M8767 registers */
enum s5m8767_reg {
S5M8767_REG_ID,
S5M8767_REG_INT1,
S5M8767_REG_INT2,
S5M8767_REG_INT3,
S5M8767_REG_INT1M,
S5M8767_REG_INT2M,
S5M8767_REG_INT3M,
S5M8767_REG_STATUS1,
S5M8767_REG_STATUS2,
S5M8767_REG_STATUS3,
S5M8767_REG_CTRL1,
S5M8767_REG_CTRL2,
S5M8767_REG_LOWBAT1,
S5M8767_REG_LOWBAT2,
S5M8767_REG_BUCHG,
S5M8767_REG_DVSRAMP,
S5M8767_REG_DVSTIMER2 = 0x10,
S5M8767_REG_DVSTIMER3,
S5M8767_REG_DVSTIMER4,
S5M8767_REG_LDO1,
S5M8767_REG_LDO2,
S5M8767_REG_LDO3,
S5M8767_REG_LDO4,
S5M8767_REG_LDO5,
S5M8767_REG_LDO6,
S5M8767_REG_LDO7,
S5M8767_REG_LDO8,
S5M8767_REG_LDO9,
S5M8767_REG_LDO10,
S5M8767_REG_LDO11,
S5M8767_REG_LDO12,
S5M8767_REG_LDO13,
S5M8767_REG_LDO14 = 0x20,
S5M8767_REG_LDO15,
S5M8767_REG_LDO16,
S5M8767_REG_LDO17,
S5M8767_REG_LDO18,
S5M8767_REG_LDO19,
S5M8767_REG_LDO20,
S5M8767_REG_LDO21,
S5M8767_REG_LDO22,
S5M8767_REG_LDO23,
S5M8767_REG_LDO24,
S5M8767_REG_LDO25,
S5M8767_REG_LDO26,
S5M8767_REG_LDO27,
S5M8767_REG_LDO28,
S5M8767_REG_UVLO = 0x31,
S5M8767_REG_BUCK1CTRL1,
S5M8767_REG_BUCK1CTRL2,
S5M8767_REG_BUCK2CTRL,
S5M8767_REG_BUCK2DVS1,
S5M8767_REG_BUCK2DVS2,
S5M8767_REG_BUCK2DVS3,
S5M8767_REG_BUCK2DVS4,
S5M8767_REG_BUCK2DVS5,
S5M8767_REG_BUCK2DVS6,
S5M8767_REG_BUCK2DVS7,
S5M8767_REG_BUCK2DVS8,
S5M8767_REG_BUCK3CTRL,
S5M8767_REG_BUCK3DVS1,
S5M8767_REG_BUCK3DVS2,
S5M8767_REG_BUCK3DVS3,
S5M8767_REG_BUCK3DVS4,
S5M8767_REG_BUCK3DVS5,
S5M8767_REG_BUCK3DVS6,
S5M8767_REG_BUCK3DVS7,
S5M8767_REG_BUCK3DVS8,
S5M8767_REG_BUCK4CTRL,
S5M8767_REG_BUCK4DVS1,
S5M8767_REG_BUCK4DVS2,
S5M8767_REG_BUCK4DVS3,
S5M8767_REG_BUCK4DVS4,
S5M8767_REG_BUCK4DVS5,
S5M8767_REG_BUCK4DVS6,
S5M8767_REG_BUCK4DVS7,
S5M8767_REG_BUCK4DVS8,
S5M8767_REG_BUCK5CTRL1,
S5M8767_REG_BUCK5CTRL2,
S5M8767_REG_BUCK5CTRL3,
S5M8767_REG_BUCK5CTRL4,
S5M8767_REG_BUCK5CTRL5,
S5M8767_REG_BUCK6CTRL1,
S5M8767_REG_BUCK6CTRL2,
S5M8767_REG_BUCK7CTRL1,
S5M8767_REG_BUCK7CTRL2,
S5M8767_REG_BUCK8CTRL1,
S5M8767_REG_BUCK8CTRL2,
S5M8767_REG_BUCK9CTRL1,
S5M8767_REG_BUCK9CTRL2,
S5M8767_REG_LDO1CTRL,
S5M8767_REG_LDO2_1CTRL,
S5M8767_REG_LDO2_2CTRL,
S5M8767_REG_LDO2_3CTRL,
S5M8767_REG_LDO2_4CTRL,
S5M8767_REG_LDO3CTRL,
S5M8767_REG_LDO4CTRL,
S5M8767_REG_LDO5CTRL,
S5M8767_REG_LDO6CTRL,
S5M8767_REG_LDO7CTRL,
S5M8767_REG_LDO8CTRL,
S5M8767_REG_LDO9CTRL,
S5M8767_REG_LDO10CTRL,
S5M8767_REG_LDO11CTRL,
S5M8767_REG_LDO12CTRL,
S5M8767_REG_LDO13CTRL,
S5M8767_REG_LDO14CTRL,
S5M8767_REG_LDO15CTRL,
S5M8767_REG_LDO16CTRL,
S5M8767_REG_LDO17CTRL,
S5M8767_REG_LDO18CTRL,
S5M8767_REG_LDO19CTRL,
S5M8767_REG_LDO20CTRL,
S5M8767_REG_LDO21CTRL,
S5M8767_REG_LDO22CTRL,
S5M8767_REG_LDO23CTRL,
S5M8767_REG_LDO24CTRL,
S5M8767_REG_LDO25CTRL,
S5M8767_REG_LDO26CTRL,
S5M8767_REG_LDO27CTRL,
S5M8767_REG_LDO28CTRL,
};
/* S5M8763 registers */
enum s5m8763_reg {
S5M8763_REG_IRQ1,
S5M8763_REG_IRQ2,
S5M8763_REG_IRQ3,
S5M8763_REG_IRQ4,
S5M8763_REG_IRQM1,
S5M8763_REG_IRQM2,
S5M8763_REG_IRQM3,
S5M8763_REG_IRQM4,
S5M8763_REG_STATUS1,
S5M8763_REG_STATUS2,
S5M8763_REG_STATUSM1,
S5M8763_REG_STATUSM2,
S5M8763_REG_CHGR1,
S5M8763_REG_CHGR2,
S5M8763_REG_LDO_ACTIVE_DISCHARGE1,
S5M8763_REG_LDO_ACTIVE_DISCHARGE2,
S5M8763_REG_BUCK_ACTIVE_DISCHARGE3,
S5M8763_REG_ONOFF1,
S5M8763_REG_ONOFF2,
S5M8763_REG_ONOFF3,
S5M8763_REG_ONOFF4,
S5M8763_REG_BUCK1_VOLTAGE1,
S5M8763_REG_BUCK1_VOLTAGE2,
S5M8763_REG_BUCK1_VOLTAGE3,
S5M8763_REG_BUCK1_VOLTAGE4,
S5M8763_REG_BUCK2_VOLTAGE1,
S5M8763_REG_BUCK2_VOLTAGE2,
S5M8763_REG_BUCK3,
S5M8763_REG_BUCK4,
S5M8763_REG_LDO1_LDO2,
S5M8763_REG_LDO3,
S5M8763_REG_LDO4,
S5M8763_REG_LDO5,
S5M8763_REG_LDO6,
S5M8763_REG_LDO7,
S5M8763_REG_LDO7_LDO8,
S5M8763_REG_LDO9_LDO10,
S5M8763_REG_LDO11,
S5M8763_REG_LDO12,
S5M8763_REG_LDO13,
S5M8763_REG_LDO14,
S5M8763_REG_LDO15,
S5M8763_REG_LDO16,
S5M8763_REG_BKCHR,
S5M8763_REG_LBCNFG1,
S5M8763_REG_LBCNFG2,
};
enum s5m8767_irq {
S5M8767_IRQ_PWRR,
S5M8767_IRQ_PWRF,
S5M8767_IRQ_PWR1S,
S5M8767_IRQ_JIGR,
S5M8767_IRQ_JIGF,
S5M8767_IRQ_LOWBAT2,
S5M8767_IRQ_LOWBAT1,
S5M8767_IRQ_MRB,
S5M8767_IRQ_DVSOK2,
S5M8767_IRQ_DVSOK3,
S5M8767_IRQ_DVSOK4,
S5M8767_IRQ_RTC60S,
S5M8767_IRQ_RTCA1,
S5M8767_IRQ_RTCA2,
S5M8767_IRQ_SMPL,
S5M8767_IRQ_RTC1S,
S5M8767_IRQ_WTSR,
S5M8767_IRQ_NR,
};
#define S5M8767_IRQ_PWRR_MASK (1 << 0)
#define S5M8767_IRQ_PWRF_MASK (1 << 1)
#define S5M8767_IRQ_PWR1S_MASK (1 << 3)
#define S5M8767_IRQ_JIGR_MASK (1 << 4)
#define S5M8767_IRQ_JIGF_MASK (1 << 5)
#define S5M8767_IRQ_LOWBAT2_MASK (1 << 6)
#define S5M8767_IRQ_LOWBAT1_MASK (1 << 7)
#define S5M8767_IRQ_MRB_MASK (1 << 2)
#define S5M8767_IRQ_DVSOK2_MASK (1 << 3)
#define S5M8767_IRQ_DVSOK3_MASK (1 << 4)
#define S5M8767_IRQ_DVSOK4_MASK (1 << 5)
#define S5M8767_IRQ_RTC60S_MASK (1 << 0)
#define S5M8767_IRQ_RTCA1_MASK (1 << 1)
#define S5M8767_IRQ_RTCA2_MASK (1 << 2)
#define S5M8767_IRQ_SMPL_MASK (1 << 3)
#define S5M8767_IRQ_RTC1S_MASK (1 << 4)
#define S5M8767_IRQ_WTSR_MASK (1 << 5)
enum s5m8763_irq {
S5M8763_IRQ_DCINF,
S5M8763_IRQ_DCINR,
S5M8763_IRQ_JIGF,
S5M8763_IRQ_JIGR,
S5M8763_IRQ_PWRONF,
S5M8763_IRQ_PWRONR,
S5M8763_IRQ_WTSREVNT,
S5M8763_IRQ_SMPLEVNT,
S5M8763_IRQ_ALARM1,
S5M8763_IRQ_ALARM0,
S5M8763_IRQ_ONKEY1S,
S5M8763_IRQ_TOPOFFR,
S5M8763_IRQ_DCINOVPR,
S5M8763_IRQ_CHGRSTF,
S5M8763_IRQ_DONER,
S5M8763_IRQ_CHGFAULT,
S5M8763_IRQ_LOBAT1,
S5M8763_IRQ_LOBAT2,
S5M8763_IRQ_NR,
};
#define S5M8763_IRQ_DCINF_MASK (1 << 2)
#define S5M8763_IRQ_DCINR_MASK (1 << 3)
#define S5M8763_IRQ_JIGF_MASK (1 << 4)
#define S5M8763_IRQ_JIGR_MASK (1 << 5)
#define S5M8763_IRQ_PWRONF_MASK (1 << 6)
#define S5M8763_IRQ_PWRONR_MASK (1 << 7)
#define S5M8763_IRQ_WTSREVNT_MASK (1 << 0)
#define S5M8763_IRQ_SMPLEVNT_MASK (1 << 1)
#define S5M8763_IRQ_ALARM1_MASK (1 << 2)
#define S5M8763_IRQ_ALARM0_MASK (1 << 3)
#define S5M8763_IRQ_ONKEY1S_MASK (1 << 0)
#define S5M8763_IRQ_TOPOFFR_MASK (1 << 2)
#define S5M8763_IRQ_DCINOVPR_MASK (1 << 3)
#define S5M8763_IRQ_CHGRSTF_MASK (1 << 4)
#define S5M8763_IRQ_DONER_MASK (1 << 5)
#define S5M8763_IRQ_CHGFAULT_MASK (1 << 7)
#define S5M8763_IRQ_LOBAT1_MASK (1 << 0)
#define S5M8763_IRQ_LOBAT2_MASK (1 << 1)
#define S5M8763_ENRAMP (1 << 4)
/**
* struct s5m87xx_dev - s5m87xx master device for sub-drivers
* @dev: master device of the chip (can be used to access platform data)
* @i2c: i2c client private data for regulator
* @rtc: i2c client private data for rtc
* @iolock: mutex for serializing io access
* @irqlock: mutex for buslock
* @irq_base: base IRQ number for s5m87xx, required for IRQs
* @irq: generic IRQ number for s5m87xx
* @ono: power onoff IRQ number for s5m87xx
* @irq_masks_cur: currently active value
* @irq_masks_cache: cached hardware value
* @type: indicate which s5m87xx "variant" is used
*/
struct s5m87xx_dev {
struct device *dev;
struct regmap *regmap;
struct i2c_client *i2c;
struct i2c_client *rtc;
struct mutex iolock;
struct mutex irqlock;
int device_type;
int irq_base;
int irq;
int ono;
u8 irq_masks_cur[NUM_IRQ_REGS];
u8 irq_masks_cache[NUM_IRQ_REGS];
int type;
bool wakeup;
};
int s5m_irq_init(struct s5m87xx_dev *s5m87xx);
void s5m_irq_exit(struct s5m87xx_dev *s5m87xx);
int s5m_irq_resume(struct s5m87xx_dev *s5m87xx);
extern int s5m_reg_read(struct s5m87xx_dev *s5m87xx, u8 reg, void *dest);
extern int s5m_bulk_read(struct s5m87xx_dev *s5m87xx, u8 reg, int count, u8 *buf);
extern int s5m_reg_write(struct s5m87xx_dev *s5m87xx, u8 reg, u8 value);
extern int s5m_bulk_write(struct s5m87xx_dev *s5m87xx, u8 reg, int count, u8 *buf);
extern int s5m_reg_update(struct s5m87xx_dev *s5m87xx, u8 reg, u8 val, u8 mask);
struct s5m_platform_data {
struct s5m_regulator_data *regulators;
int device_type;
int num_regulators;
int irq_base;
int (*cfg_pmic_irq)(void);
int ono;
bool wakeup;
bool buck_voltage_lock;
int buck_gpios[3];
int buck2_voltage[8];
bool buck2_gpiodvs;
int buck3_voltage[8];
bool buck3_gpiodvs;
int buck4_voltage[8];
bool buck4_gpiodvs;
int buck_set1;
int buck_set2;
int buck_set3;
int buck2_enable;
int buck3_enable;
int buck4_enable;
int buck_default_idx;
int buck2_default_idx;
int buck3_default_idx;
int buck4_default_idx;
int buck_ramp_delay;
bool buck2_ramp_enable;
bool buck3_ramp_enable;
bool buck4_ramp_enable;
};
#endif /* __LINUX_MFD_S5M_CORE_H */

View file

@ -0,0 +1,100 @@
/* s5m87xx.h
*
* Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef __LINUX_MFD_S5M_PMIC_H
#define __LINUX_MFD_S5M_PMIC_H
#include <linux/regulator/machine.h>
/* S5M8767 regulator ids */
enum s5m8767_regulators {
S5M8767_LDO1,
S5M8767_LDO2,
S5M8767_LDO3,
S5M8767_LDO4,
S5M8767_LDO5,
S5M8767_LDO6,
S5M8767_LDO7,
S5M8767_LDO8,
S5M8767_LDO9,
S5M8767_LDO10,
S5M8767_LDO11,
S5M8767_LDO12,
S5M8767_LDO13,
S5M8767_LDO14,
S5M8767_LDO15,
S5M8767_LDO16,
S5M8767_LDO17,
S5M8767_LDO18,
S5M8767_LDO19,
S5M8767_LDO20,
S5M8767_LDO21,
S5M8767_LDO22,
S5M8767_LDO23,
S5M8767_LDO24,
S5M8767_LDO25,
S5M8767_LDO26,
S5M8767_LDO27,
S5M8767_LDO28,
S5M8767_BUCK1,
S5M8767_BUCK2,
S5M8767_BUCK3,
S5M8767_BUCK4,
S5M8767_BUCK5,
S5M8767_BUCK6,
S5M8767_BUCK7,
S5M8767_BUCK8,
S5M8767_BUCK9,
S5M8767_AP_EN32KHZ,
S5M8767_CP_EN32KHZ,
S5M8767_REG_MAX,
};
/* S5M8763 regulator ids */
enum s5m8763_regulators {
S5M8763_LDO1,
S5M8763_LDO2,
S5M8763_LDO3,
S5M8763_LDO4,
S5M8763_LDO5,
S5M8763_LDO6,
S5M8763_LDO7,
S5M8763_LDO8,
S5M8763_LDO9,
S5M8763_LDO10,
S5M8763_LDO11,
S5M8763_LDO12,
S5M8763_LDO13,
S5M8763_LDO14,
S5M8763_LDO15,
S5M8763_LDO16,
S5M8763_BUCK1,
S5M8763_BUCK2,
S5M8763_BUCK3,
S5M8763_BUCK4,
S5M8763_AP_EN32KHZ,
S5M8763_CP_EN32KHZ,
S5M8763_ENCHGVI,
S5M8763_ESAFEUSB1,
S5M8763_ESAFEUSB2,
};
/**
* s5m87xx_regulator_data - regulator data
* @id: regulator id
* @initdata: regulator init data (contraints, supplies, ...)
*/
struct s5m_regulator_data {
int id;
struct regulator_init_data *initdata;
};
#endif /* __LINUX_MFD_S5M_PMIC_H */

View file

@ -0,0 +1,84 @@
/*
* s5m-rtc.h
*
* Copyright (c) 2011 Samsung Electronics Co., Ltd
* http://www.samsung.com
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
*/
#ifndef __LINUX_MFD_S5M_RTC_H
#define __LINUX_MFD_S5M_RTC_H
enum s5m87xx_rtc_reg {
S5M87XX_RTC_SEC,
S5M87XX_RTC_MIN,
S5M87XX_RTC_HOUR,
S5M87XX_RTC_WEEKDAY,
S5M87XX_RTC_DATE,
S5M87XX_RTC_MONTH,
S5M87XX_RTC_YEAR1,
S5M87XX_RTC_YEAR2,
S5M87XX_ALARM0_SEC,
S5M87XX_ALARM0_MIN,
S5M87XX_ALARM0_HOUR,
S5M87XX_ALARM0_WEEKDAY,
S5M87XX_ALARM0_DATE,
S5M87XX_ALARM0_MONTH,
S5M87XX_ALARM0_YEAR1,
S5M87XX_ALARM0_YEAR2,
S5M87XX_ALARM1_SEC,
S5M87XX_ALARM1_MIN,
S5M87XX_ALARM1_HOUR,
S5M87XX_ALARM1_WEEKDAY,
S5M87XX_ALARM1_DATE,
S5M87XX_ALARM1_MONTH,
S5M87XX_ALARM1_YEAR1,
S5M87XX_ALARM1_YEAR2,
S5M87XX_ALARM0_CONF,
S5M87XX_ALARM1_CONF,
S5M87XX_RTC_STATUS,
S5M87XX_WTSR_SMPL_CNTL,
S5M87XX_RTC_UDR_CON,
};
#define RTC_I2C_ADDR (0x0C >> 1)
#define HOUR_12 (1 << 7)
#define HOUR_AMPM (1 << 6)
#define HOUR_PM (1 << 5)
#define ALARM0_STATUS (1 << 1)
#define ALARM1_STATUS (1 << 2)
#define UPDATE_AD (1 << 0)
/* RTC Control Register */
#define BCD_EN_SHIFT 0
#define BCD_EN_MASK (1 << BCD_EN_SHIFT)
#define MODEL24_SHIFT 1
#define MODEL24_MASK (1 << MODEL24_SHIFT)
/* RTC Update Register1 */
#define RTC_UDR_SHIFT 0
#define RTC_UDR_MASK (1 << RTC_UDR_SHIFT)
/* RTC Hour register */
#define HOUR_PM_SHIFT 6
#define HOUR_PM_MASK (1 << HOUR_PM_SHIFT)
/* RTC Alarm Enable */
#define ALARM_ENABLE_SHIFT 7
#define ALARM_ENABLE_MASK (1 << ALARM_ENABLE_SHIFT)
enum {
RTC_SEC = 0,
RTC_MIN,
RTC_HOUR,
RTC_WEEKDAY,
RTC_DATE,
RTC_MONTH,
RTC_YEAR1,
RTC_YEAR2,
};
#endif /* __LINUX_MFD_S5M_RTC_H */

View file

@ -20,6 +20,8 @@ enum stmpe_block {
};
enum stmpe_partnum {
STMPE610,
STMPE801,
STMPE811,
STMPE1601,
STMPE2401,
@ -50,17 +52,20 @@ enum {
struct stmpe_variant_info;
struct stmpe_client_info;
/**
* struct stmpe - STMPE MFD structure
* @lock: lock protecting I/O operations
* @irq_lock: IRQ bus lock
* @dev: device, mostly for dev_dbg()
* @i2c: i2c client
* @client: client - i2c or spi
* @ci: client specific information
* @partnum: part number
* @variant: the detected STMPE model number
* @regs: list of addresses of registers which are at different addresses on
* different variants. Indexed by one of STMPE_IDX_*.
* @irq: irq number for stmpe
* @irq_base: starting IRQ number for internal IRQs
* @num_gpios: number of gpios, differs for variants
* @ier: cache of IER registers for bus_lock
@ -71,11 +76,13 @@ struct stmpe {
struct mutex lock;
struct mutex irq_lock;
struct device *dev;
struct i2c_client *i2c;
void *client;
struct stmpe_client_info *ci;
enum stmpe_partnum partnum;
struct stmpe_variant_info *variant;
const u8 *regs;
int irq;
int irq_base;
int num_gpios;
u8 ier[2];
@ -183,6 +190,9 @@ struct stmpe_ts_platform_data {
* @autosleep_timeout: inactivity timeout in milliseconds for autosleep
* @irq_base: base IRQ number. %STMPE_NR_IRQS irqs will be used, or
* %STMPE_NR_INTERNAL_IRQS if the GPIO driver is not used.
* @irq_over_gpio: true if gpio is used to get irq
* @irq_gpio: gpio number over which irq will be requested (significant only if
* irq_over_gpio is true)
* @gpio: GPIO-specific platform data
* @keypad: keypad-specific platform data
* @ts: touchscreen-specific platform data
@ -194,6 +204,8 @@ struct stmpe_platform_data {
unsigned int irq_trigger;
bool irq_invert_polarity;
bool autosleep;
bool irq_over_gpio;
int irq_gpio;
int autosleep_timeout;
struct stmpe_gpio_platform_data *gpio;

View file

@ -104,6 +104,9 @@
#define UCB_MODE_DYN_VFLAG_ENA (1 << 12)
#define UCB_MODE_AUD_OFF_CAN (1 << 13)
struct ucb1x00_plat_data {
int gpio_base;
};
struct ucb1x00_irq {
void *devid;
@ -116,7 +119,7 @@ struct ucb1x00 {
unsigned int irq;
struct semaphore adc_sem;
spinlock_t io_lock;
u16 id;
const struct mcp_device_id *id;
u16 io_dir;
u16 io_out;
u16 adc_cr;

View file

@ -436,6 +436,17 @@ struct spi_device_id {
__attribute__((aligned(sizeof(kernel_ulong_t))));
};
/* mcp */
#define MCP_NAME_SIZE 20
#define MCP_MODULE_PREFIX "mcp:"
struct mcp_device_id {
char name[MCP_NAME_SIZE];
kernel_ulong_t driver_data /* Data private to the driver */
__attribute__((aligned(sizeof(kernel_ulong_t))));
};
/* dmi */
enum dmi_field {
DMI_NONE,

View file

@ -774,6 +774,15 @@ static int do_spi_entry(const char *filename, struct spi_device_id *id,
return 1;
}
/* Looks like: mcp:S */
static int do_mcp_entry(const char *filename, struct mcp_device_id *id,
char *alias)
{
sprintf(alias, MCP_MODULE_PREFIX "%s", id->name);
return 1;
}
static const struct dmifield {
const char *prefix;
int field;
@ -1095,6 +1104,10 @@ void handle_moddevtable(struct module *mod, struct elf_info *info,
do_table(symval, sym->st_size,
sizeof(struct spi_device_id), "spi",
do_spi_entry, mod);
else if (sym_is(symname, "__mod_mcp_device_table"))
do_table(symval, sym->st_size,
sizeof(struct mcp_device_id), "mcp",
do_mcp_entry, mod);
else if (sym_is(symname, "__mod_dmi_device_table"))
do_table(symval, sym->st_size,
sizeof(struct dmi_system_id), "dmi",