mirror of
https://github.com/joel16/android_kernel_sony_msm8994.git
synced 2024-11-27 06:01:12 +00:00
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:
commit
21ebd6c68b
78
Documentation/devicetree/bindings/mfd/mc13xxx.txt
Normal file
78
Documentation/devicetree/bindings/mfd/mc13xxx.txt
Normal 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;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
47
Documentation/devicetree/bindings/mfd/twl-familly.txt
Normal file
47
Documentation/devicetree/bindings/mfd/twl-familly.txt
Normal 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>;
|
||||
};
|
||||
};
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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,
|
||||
|
@ -17,6 +17,8 @@ struct mcp_plat_data {
|
||||
u32 mccr1;
|
||||
unsigned int sclk_rate;
|
||||
int gpio_base;
|
||||
const char *codec;
|
||||
void *codec_pdata;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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));
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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 \
|
||||
|
@ -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;
|
||||
|
@ -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>
|
||||
|
||||
/**
|
||||
|
@ -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
|
||||
|
@ -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
372
drivers/leds/leds-max8997.c
Normal 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");
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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"
|
||||
|
@ -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>
|
||||
|
||||
/*
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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>");
|
||||
|
@ -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>");
|
||||
|
@ -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, }
|
||||
|
@ -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),
|
||||
|
@ -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)
|
||||
|
@ -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"
|
||||
|
@ -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),
|
||||
|
@ -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);
|
||||
|
@ -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");
|
||||
|
@ -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);
|
||||
|
@ -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
176
drivers/mfd/s5m-core.c
Normal 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
487
drivers/mfd/s5m-irq.c
Normal 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);
|
||||
}
|
@ -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
109
drivers/mfd/stmpe-i2c.c
Normal 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
150
drivers/mfd/stmpe-spi.c
Normal 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>");
|
@ -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>");
|
||||
|
@ -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
|
||||
|
@ -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");
|
||||
|
@ -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");
|
||||
|
@ -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");
|
||||
|
@ -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 }
|
||||
};
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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");
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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");
|
||||
|
@ -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)
|
||||
|
@ -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>");
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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, }
|
||||
};
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
},
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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
505
drivers/misc/max8997-muic.c
Normal 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");
|
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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),
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
@ -203,6 +203,8 @@ struct max8925_chip {
|
||||
int irq_base;
|
||||
int core_irq;
|
||||
int tsc_irq;
|
||||
|
||||
unsigned int wakeup_flag;
|
||||
};
|
||||
|
||||
struct max8925_backlight_pdata {
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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 *);
|
||||
|
373
include/linux/mfd/s5m87xx/s5m-core.h
Normal file
373
include/linux/mfd/s5m87xx/s5m-core.h
Normal 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 */
|
100
include/linux/mfd/s5m87xx/s5m-pmic.h
Normal file
100
include/linux/mfd/s5m87xx/s5m-pmic.h
Normal 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 */
|
84
include/linux/mfd/s5m87xx/s5m-rtc.h
Normal file
84
include/linux/mfd/s5m87xx/s5m-rtc.h
Normal 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 */
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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",
|
||||
|
Loading…
Reference in New Issue
Block a user