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: (57 commits) regulator: Fix 88pm8607.c printk format warning input: Add support for Qualcomm PMIC8XXX power key input: Add Qualcomm pm8xxx keypad controller driver mfd: Add omap-usbhs runtime PM support mfd: Fix ASIC3 SD Host Controller Configuration size mfd: Fix omap_usbhs_alloc_children error handling mfd: Fix omap usbhs crash when rmmoding ehci or ohci mfd: Add ASIC3 LED support leds: Add ASIC3 LED support mfd: Update twl4030-code maintainer e-mail address mfd: Correct the name and bitmask for ab8500-gpadc BTempPullUp mfd: Add manual ab8500-gpadc batt temp activation for AB8500 3.0 mfd: Provide ab8500-core enumerators for chip cuts mfd: Check twl4030-power remove script error condition after i2cwrite mfd: Fix twl6030 irq definitions mfd: Add phoenix lite (twl6025) support to twl6030 mfd: Avoid to use constraint name in 88pm860x regulator driver mfd: Remove checking on max8925 regulator[0] mfd: Remove unused parameter from 88pm860x API mfd: Avoid to allocate 88pm860x static platform data ...
This commit is contained in:
commit
9f1912c48c
@ -931,6 +931,8 @@ F: drivers/mmc/host/msm_sdcc.h
|
||||
F: drivers/tty/serial/msm_serial.h
|
||||
F: drivers/tty/serial/msm_serial.c
|
||||
F: drivers/platform/msm/
|
||||
F: drivers/*/pm8???-*
|
||||
F: include/linux/mfd/pm8xxx/
|
||||
T: git git://codeaurora.org/quic/kernel/davidb/linux-msm.git
|
||||
S: Maintained
|
||||
|
||||
|
@ -729,7 +729,7 @@ static struct twl4030_resconfig twl4030_rconfig[] __initdata = {
|
||||
{ .resource = RES_RESET, .devgroup = -1,
|
||||
.type = 1, .type2 = -1, .remap_off = -1, .remap_sleep = -1
|
||||
},
|
||||
{ .resource = RES_Main_Ref, .devgroup = -1,
|
||||
{ .resource = RES_MAIN_REF, .devgroup = -1,
|
||||
.type = 1, .type2 = -1, .remap_off = -1, .remap_sleep = -1
|
||||
},
|
||||
{ 0, 0},
|
||||
|
@ -27,7 +27,6 @@
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <linux/timb_dma.h>
|
||||
@ -685,7 +684,7 @@ static irqreturn_t td_irq(int irq, void *devid)
|
||||
|
||||
static int __devinit td_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct timb_dma_platform_data *pdata = mfd_get_data(pdev);
|
||||
struct timb_dma_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct timb_dma *td;
|
||||
struct resource *iomem;
|
||||
int irq;
|
||||
|
@ -15,7 +15,6 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/slab.h>
|
||||
@ -150,7 +149,7 @@ static int __devinit ttl_probe(struct platform_device *pdev)
|
||||
struct resource *res;
|
||||
int ret;
|
||||
|
||||
pdata = mfd_get_data(pdev);
|
||||
pdata = pdev->dev.platform_data;
|
||||
if (!pdata) {
|
||||
dev_err(dev, "no platform data\n");
|
||||
ret = -ENXIO;
|
||||
|
@ -27,7 +27,6 @@
|
||||
#include <linux/pci.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/mfd/rdc321x.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
struct rdc321x_gpio {
|
||||
@ -136,7 +135,7 @@ static int __devinit rdc321x_gpio_probe(struct platform_device *pdev)
|
||||
struct rdc321x_gpio *rdc321x_gpio_dev;
|
||||
struct rdc321x_gpio_pdata *pdata;
|
||||
|
||||
pdata = mfd_get_data(pdev);
|
||||
pdata = pdev->dev.platform_data;
|
||||
if (!pdata) {
|
||||
dev_err(&pdev->dev, "no platform data supplied\n");
|
||||
return -ENODEV;
|
||||
|
@ -23,7 +23,6 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/timb_gpio.h>
|
||||
@ -229,7 +228,7 @@ static int __devinit timbgpio_probe(struct platform_device *pdev)
|
||||
struct gpio_chip *gc;
|
||||
struct timbgpio *tgpio;
|
||||
struct resource *iomem;
|
||||
struct timbgpio_platform_data *pdata = mfd_get_data(pdev);
|
||||
struct timbgpio_platform_data *pdata = pdev->dev.platform_data;
|
||||
int irq = platform_get_irq(pdev, 0);
|
||||
|
||||
if (!pdata || pdata->nr_pins > 32) {
|
||||
@ -320,13 +319,14 @@ err_mem:
|
||||
static int __devexit timbgpio_remove(struct platform_device *pdev)
|
||||
{
|
||||
int err;
|
||||
struct timbgpio_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct timbgpio *tgpio = platform_get_drvdata(pdev);
|
||||
struct resource *iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
int irq = platform_get_irq(pdev, 0);
|
||||
|
||||
if (irq >= 0 && tgpio->irq_base > 0) {
|
||||
int i;
|
||||
for (i = 0; i < tgpio->gpio.ngpio; i++) {
|
||||
for (i = 0; i < pdata->nr_pins; i++) {
|
||||
irq_set_chip(tgpio->irq_base + i, NULL);
|
||||
irq_set_chip_data(tgpio->irq_base + i, NULL);
|
||||
}
|
||||
|
@ -49,7 +49,6 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/wait.h>
|
||||
@ -306,7 +305,7 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev)
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
pdata = mfd_get_data(pdev);
|
||||
pdata = pdev->dev.platform_data;
|
||||
if (pdata) {
|
||||
i2c->regstep = pdata->regstep;
|
||||
i2c->clock_khz = pdata->clock_khz;
|
||||
|
@ -34,7 +34,6 @@
|
||||
#include <linux/errno.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/wait.h>
|
||||
@ -705,7 +704,7 @@ static int __devinit xiic_i2c_probe(struct platform_device *pdev)
|
||||
if (irq < 0)
|
||||
goto resource_missing;
|
||||
|
||||
pdata = mfd_get_data(pdev);
|
||||
pdata = (struct xiic_i2c_platform_data *) pdev->dev.platform_data;
|
||||
if (!pdata)
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -412,6 +412,17 @@ config KEYBOARD_PXA930_ROTARY
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called pxa930_rotary.
|
||||
|
||||
config KEYBOARD_PMIC8XXX
|
||||
tristate "Qualcomm PMIC8XXX keypad support"
|
||||
depends on MFD_PM8XXX
|
||||
help
|
||||
Say Y here if you want to enable the driver for the PMIC8XXX
|
||||
keypad provided as a reference design from Qualcomm. This is intended
|
||||
to support upto 18x8 matrix based keypad design.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will
|
||||
be called pmic8xxx-keypad.
|
||||
|
||||
config KEYBOARD_SAMSUNG
|
||||
tristate "Samsung keypad support"
|
||||
depends on SAMSUNG_DEV_KEYPAD
|
||||
|
@ -34,6 +34,7 @@ obj-$(CONFIG_KEYBOARD_NOMADIK) += nomadik-ske-keypad.o
|
||||
obj-$(CONFIG_KEYBOARD_OMAP) += omap-keypad.o
|
||||
obj-$(CONFIG_KEYBOARD_OMAP4) += omap4-keypad.o
|
||||
obj-$(CONFIG_KEYBOARD_OPENCORES) += opencores-kbd.o
|
||||
obj-$(CONFIG_KEYBOARD_PMIC8XXX) += pmic8xxx-keypad.o
|
||||
obj-$(CONFIG_KEYBOARD_PXA27x) += pxa27x_keypad.o
|
||||
obj-$(CONFIG_KEYBOARD_PXA930_ROTARY) += pxa930_rotary.o
|
||||
obj-$(CONFIG_KEYBOARD_QT1070) += qt1070.o
|
||||
|
799
drivers/input/keyboard/pmic8xxx-keypad.c
Normal file
799
drivers/input/keyboard/pmic8xxx-keypad.c
Normal file
@ -0,0 +1,799 @@
|
||||
/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#include <linux/mfd/pm8xxx/core.h>
|
||||
#include <linux/mfd/pm8xxx/gpio.h>
|
||||
#include <linux/input/pmic8xxx-keypad.h>
|
||||
|
||||
#define PM8XXX_MAX_ROWS 18
|
||||
#define PM8XXX_MAX_COLS 8
|
||||
#define PM8XXX_ROW_SHIFT 3
|
||||
#define PM8XXX_MATRIX_MAX_SIZE (PM8XXX_MAX_ROWS * PM8XXX_MAX_COLS)
|
||||
|
||||
#define PM8XXX_MIN_ROWS 5
|
||||
#define PM8XXX_MIN_COLS 5
|
||||
|
||||
#define MAX_SCAN_DELAY 128
|
||||
#define MIN_SCAN_DELAY 1
|
||||
|
||||
/* in nanoseconds */
|
||||
#define MAX_ROW_HOLD_DELAY 122000
|
||||
#define MIN_ROW_HOLD_DELAY 30500
|
||||
|
||||
#define MAX_DEBOUNCE_TIME 20
|
||||
#define MIN_DEBOUNCE_TIME 5
|
||||
|
||||
#define KEYP_CTRL 0x148
|
||||
|
||||
#define KEYP_CTRL_EVNTS BIT(0)
|
||||
#define KEYP_CTRL_EVNTS_MASK 0x3
|
||||
|
||||
#define KEYP_CTRL_SCAN_COLS_SHIFT 5
|
||||
#define KEYP_CTRL_SCAN_COLS_MIN 5
|
||||
#define KEYP_CTRL_SCAN_COLS_BITS 0x3
|
||||
|
||||
#define KEYP_CTRL_SCAN_ROWS_SHIFT 2
|
||||
#define KEYP_CTRL_SCAN_ROWS_MIN 5
|
||||
#define KEYP_CTRL_SCAN_ROWS_BITS 0x7
|
||||
|
||||
#define KEYP_CTRL_KEYP_EN BIT(7)
|
||||
|
||||
#define KEYP_SCAN 0x149
|
||||
|
||||
#define KEYP_SCAN_READ_STATE BIT(0)
|
||||
#define KEYP_SCAN_DBOUNCE_SHIFT 1
|
||||
#define KEYP_SCAN_PAUSE_SHIFT 3
|
||||
#define KEYP_SCAN_ROW_HOLD_SHIFT 6
|
||||
|
||||
#define KEYP_TEST 0x14A
|
||||
|
||||
#define KEYP_TEST_CLEAR_RECENT_SCAN BIT(6)
|
||||
#define KEYP_TEST_CLEAR_OLD_SCAN BIT(5)
|
||||
#define KEYP_TEST_READ_RESET BIT(4)
|
||||
#define KEYP_TEST_DTEST_EN BIT(3)
|
||||
#define KEYP_TEST_ABORT_READ BIT(0)
|
||||
|
||||
#define KEYP_TEST_DBG_SELECT_SHIFT 1
|
||||
|
||||
/* bits of these registers represent
|
||||
* '0' for key press
|
||||
* '1' for key release
|
||||
*/
|
||||
#define KEYP_RECENT_DATA 0x14B
|
||||
#define KEYP_OLD_DATA 0x14C
|
||||
|
||||
#define KEYP_CLOCK_FREQ 32768
|
||||
|
||||
/**
|
||||
* struct pmic8xxx_kp - internal keypad data structure
|
||||
* @pdata - keypad platform data pointer
|
||||
* @input - input device pointer for keypad
|
||||
* @key_sense_irq - key press/release irq number
|
||||
* @key_stuck_irq - key stuck notification irq number
|
||||
* @keycodes - array to hold the key codes
|
||||
* @dev - parent device pointer
|
||||
* @keystate - present key press/release state
|
||||
* @stuckstate - present state when key stuck irq
|
||||
* @ctrl_reg - control register value
|
||||
*/
|
||||
struct pmic8xxx_kp {
|
||||
const struct pm8xxx_keypad_platform_data *pdata;
|
||||
struct input_dev *input;
|
||||
int key_sense_irq;
|
||||
int key_stuck_irq;
|
||||
|
||||
unsigned short keycodes[PM8XXX_MATRIX_MAX_SIZE];
|
||||
|
||||
struct device *dev;
|
||||
u16 keystate[PM8XXX_MAX_ROWS];
|
||||
u16 stuckstate[PM8XXX_MAX_ROWS];
|
||||
|
||||
u8 ctrl_reg;
|
||||
};
|
||||
|
||||
static int pmic8xxx_kp_write_u8(struct pmic8xxx_kp *kp,
|
||||
u8 data, u16 reg)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = pm8xxx_writeb(kp->dev->parent, reg, data);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int pmic8xxx_kp_read(struct pmic8xxx_kp *kp,
|
||||
u8 *data, u16 reg, unsigned num_bytes)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = pm8xxx_read_buf(kp->dev->parent, reg, data, num_bytes);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int pmic8xxx_kp_read_u8(struct pmic8xxx_kp *kp,
|
||||
u8 *data, u16 reg)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = pmic8xxx_kp_read(kp, data, reg, 1);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static u8 pmic8xxx_col_state(struct pmic8xxx_kp *kp, u8 col)
|
||||
{
|
||||
/* all keys pressed on that particular row? */
|
||||
if (col == 0x00)
|
||||
return 1 << kp->pdata->num_cols;
|
||||
else
|
||||
return col & ((1 << kp->pdata->num_cols) - 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Synchronous read protocol for RevB0 onwards:
|
||||
*
|
||||
* 1. Write '1' to ReadState bit in KEYP_SCAN register
|
||||
* 2. Wait 2*32KHz clocks, so that HW can successfully enter read mode
|
||||
* synchronously
|
||||
* 3. Read rows in old array first if events are more than one
|
||||
* 4. Read rows in recent array
|
||||
* 5. Wait 4*32KHz clocks
|
||||
* 6. Write '0' to ReadState bit of KEYP_SCAN register so that hw can
|
||||
* synchronously exit read mode.
|
||||
*/
|
||||
static int pmic8xxx_chk_sync_read(struct pmic8xxx_kp *kp)
|
||||
{
|
||||
int rc;
|
||||
u8 scan_val;
|
||||
|
||||
rc = pmic8xxx_kp_read_u8(kp, &scan_val, KEYP_SCAN);
|
||||
if (rc < 0) {
|
||||
dev_err(kp->dev, "Error reading KEYP_SCAN reg, rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
scan_val |= 0x1;
|
||||
|
||||
rc = pmic8xxx_kp_write_u8(kp, scan_val, KEYP_SCAN);
|
||||
if (rc < 0) {
|
||||
dev_err(kp->dev, "Error writing KEYP_SCAN reg, rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* 2 * 32KHz clocks */
|
||||
udelay((2 * DIV_ROUND_UP(USEC_PER_SEC, KEYP_CLOCK_FREQ)) + 1);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int pmic8xxx_kp_read_data(struct pmic8xxx_kp *kp, u16 *state,
|
||||
u16 data_reg, int read_rows)
|
||||
{
|
||||
int rc, row;
|
||||
u8 new_data[PM8XXX_MAX_ROWS];
|
||||
|
||||
rc = pmic8xxx_kp_read(kp, new_data, data_reg, read_rows);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
for (row = 0; row < kp->pdata->num_rows; row++) {
|
||||
dev_dbg(kp->dev, "new_data[%d] = %d\n", row,
|
||||
new_data[row]);
|
||||
state[row] = pmic8xxx_col_state(kp, new_data[row]);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int pmic8xxx_kp_read_matrix(struct pmic8xxx_kp *kp, u16 *new_state,
|
||||
u16 *old_state)
|
||||
{
|
||||
int rc, read_rows;
|
||||
u8 scan_val;
|
||||
|
||||
if (kp->pdata->num_rows < PM8XXX_MIN_ROWS)
|
||||
read_rows = PM8XXX_MIN_ROWS;
|
||||
else
|
||||
read_rows = kp->pdata->num_rows;
|
||||
|
||||
pmic8xxx_chk_sync_read(kp);
|
||||
|
||||
if (old_state) {
|
||||
rc = pmic8xxx_kp_read_data(kp, old_state, KEYP_OLD_DATA,
|
||||
read_rows);
|
||||
if (rc < 0) {
|
||||
dev_err(kp->dev,
|
||||
"Error reading KEYP_OLD_DATA, rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
rc = pmic8xxx_kp_read_data(kp, new_state, KEYP_RECENT_DATA,
|
||||
read_rows);
|
||||
if (rc < 0) {
|
||||
dev_err(kp->dev,
|
||||
"Error reading KEYP_RECENT_DATA, rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* 4 * 32KHz clocks */
|
||||
udelay((4 * DIV_ROUND_UP(USEC_PER_SEC, KEYP_CLOCK_FREQ)) + 1);
|
||||
|
||||
rc = pmic8xxx_kp_read_u8(kp, &scan_val, KEYP_SCAN);
|
||||
if (rc < 0) {
|
||||
dev_err(kp->dev, "Error reading KEYP_SCAN reg, rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
scan_val &= 0xFE;
|
||||
rc = pmic8xxx_kp_write_u8(kp, scan_val, KEYP_SCAN);
|
||||
if (rc < 0)
|
||||
dev_err(kp->dev, "Error writing KEYP_SCAN reg, rc=%d\n", rc);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void __pmic8xxx_kp_scan_matrix(struct pmic8xxx_kp *kp, u16 *new_state,
|
||||
u16 *old_state)
|
||||
{
|
||||
int row, col, code;
|
||||
|
||||
for (row = 0; row < kp->pdata->num_rows; row++) {
|
||||
int bits_changed = new_state[row] ^ old_state[row];
|
||||
|
||||
if (!bits_changed)
|
||||
continue;
|
||||
|
||||
for (col = 0; col < kp->pdata->num_cols; col++) {
|
||||
if (!(bits_changed & (1 << col)))
|
||||
continue;
|
||||
|
||||
dev_dbg(kp->dev, "key [%d:%d] %s\n", row, col,
|
||||
!(new_state[row] & (1 << col)) ?
|
||||
"pressed" : "released");
|
||||
|
||||
code = MATRIX_SCAN_CODE(row, col, PM8XXX_ROW_SHIFT);
|
||||
|
||||
input_event(kp->input, EV_MSC, MSC_SCAN, code);
|
||||
input_report_key(kp->input,
|
||||
kp->keycodes[code],
|
||||
!(new_state[row] & (1 << col)));
|
||||
|
||||
input_sync(kp->input);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool pmic8xxx_detect_ghost_keys(struct pmic8xxx_kp *kp, u16 *new_state)
|
||||
{
|
||||
int row, found_first = -1;
|
||||
u16 check, row_state;
|
||||
|
||||
check = 0;
|
||||
for (row = 0; row < kp->pdata->num_rows; row++) {
|
||||
row_state = (~new_state[row]) &
|
||||
((1 << kp->pdata->num_cols) - 1);
|
||||
|
||||
if (hweight16(row_state) > 1) {
|
||||
if (found_first == -1)
|
||||
found_first = row;
|
||||
if (check & row_state) {
|
||||
dev_dbg(kp->dev, "detected ghost key on row[%d]"
|
||||
" and row[%d]\n", found_first, row);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
check |= row_state;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static int pmic8xxx_kp_scan_matrix(struct pmic8xxx_kp *kp, unsigned int events)
|
||||
{
|
||||
u16 new_state[PM8XXX_MAX_ROWS];
|
||||
u16 old_state[PM8XXX_MAX_ROWS];
|
||||
int rc;
|
||||
|
||||
switch (events) {
|
||||
case 0x1:
|
||||
rc = pmic8xxx_kp_read_matrix(kp, new_state, NULL);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
/* detecting ghost key is not an error */
|
||||
if (pmic8xxx_detect_ghost_keys(kp, new_state))
|
||||
return 0;
|
||||
__pmic8xxx_kp_scan_matrix(kp, new_state, kp->keystate);
|
||||
memcpy(kp->keystate, new_state, sizeof(new_state));
|
||||
break;
|
||||
case 0x3: /* two events - eventcounter is gray-coded */
|
||||
rc = pmic8xxx_kp_read_matrix(kp, new_state, old_state);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
__pmic8xxx_kp_scan_matrix(kp, old_state, kp->keystate);
|
||||
__pmic8xxx_kp_scan_matrix(kp, new_state, old_state);
|
||||
memcpy(kp->keystate, new_state, sizeof(new_state));
|
||||
break;
|
||||
case 0x2:
|
||||
dev_dbg(kp->dev, "Some key events were lost\n");
|
||||
rc = pmic8xxx_kp_read_matrix(kp, new_state, old_state);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
__pmic8xxx_kp_scan_matrix(kp, old_state, kp->keystate);
|
||||
__pmic8xxx_kp_scan_matrix(kp, new_state, old_state);
|
||||
memcpy(kp->keystate, new_state, sizeof(new_state));
|
||||
break;
|
||||
default:
|
||||
rc = -EINVAL;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* NOTE: We are reading recent and old data registers blindly
|
||||
* whenever key-stuck interrupt happens, because events counter doesn't
|
||||
* get updated when this interrupt happens due to key stuck doesn't get
|
||||
* considered as key state change.
|
||||
*
|
||||
* We are not using old data register contents after they are being read
|
||||
* because it might report the key which was pressed before the key being stuck
|
||||
* as stuck key because it's pressed status is stored in the old data
|
||||
* register.
|
||||
*/
|
||||
static irqreturn_t pmic8xxx_kp_stuck_irq(int irq, void *data)
|
||||
{
|
||||
u16 new_state[PM8XXX_MAX_ROWS];
|
||||
u16 old_state[PM8XXX_MAX_ROWS];
|
||||
int rc;
|
||||
struct pmic8xxx_kp *kp = data;
|
||||
|
||||
rc = pmic8xxx_kp_read_matrix(kp, new_state, old_state);
|
||||
if (rc < 0) {
|
||||
dev_err(kp->dev, "failed to read keypad matrix\n");
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
__pmic8xxx_kp_scan_matrix(kp, new_state, kp->stuckstate);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t pmic8xxx_kp_irq(int irq, void *data)
|
||||
{
|
||||
struct pmic8xxx_kp *kp = data;
|
||||
u8 ctrl_val, events;
|
||||
int rc;
|
||||
|
||||
rc = pmic8xxx_kp_read(kp, &ctrl_val, KEYP_CTRL, 1);
|
||||
if (rc < 0) {
|
||||
dev_err(kp->dev, "failed to read keyp_ctrl register\n");
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
events = ctrl_val & KEYP_CTRL_EVNTS_MASK;
|
||||
|
||||
rc = pmic8xxx_kp_scan_matrix(kp, events);
|
||||
if (rc < 0)
|
||||
dev_err(kp->dev, "failed to scan matrix\n");
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int __devinit pmic8xxx_kpd_init(struct pmic8xxx_kp *kp)
|
||||
{
|
||||
int bits, rc, cycles;
|
||||
u8 scan_val = 0, ctrl_val = 0;
|
||||
static const u8 row_bits[] = {
|
||||
0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 7, 7, 7,
|
||||
};
|
||||
|
||||
/* Find column bits */
|
||||
if (kp->pdata->num_cols < KEYP_CTRL_SCAN_COLS_MIN)
|
||||
bits = 0;
|
||||
else
|
||||
bits = kp->pdata->num_cols - KEYP_CTRL_SCAN_COLS_MIN;
|
||||
ctrl_val = (bits & KEYP_CTRL_SCAN_COLS_BITS) <<
|
||||
KEYP_CTRL_SCAN_COLS_SHIFT;
|
||||
|
||||
/* Find row bits */
|
||||
if (kp->pdata->num_rows < KEYP_CTRL_SCAN_ROWS_MIN)
|
||||
bits = 0;
|
||||
else
|
||||
bits = row_bits[kp->pdata->num_rows - KEYP_CTRL_SCAN_ROWS_MIN];
|
||||
|
||||
ctrl_val |= (bits << KEYP_CTRL_SCAN_ROWS_SHIFT);
|
||||
|
||||
rc = pmic8xxx_kp_write_u8(kp, ctrl_val, KEYP_CTRL);
|
||||
if (rc < 0) {
|
||||
dev_err(kp->dev, "Error writing KEYP_CTRL reg, rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
bits = (kp->pdata->debounce_ms / 5) - 1;
|
||||
|
||||
scan_val |= (bits << KEYP_SCAN_DBOUNCE_SHIFT);
|
||||
|
||||
bits = fls(kp->pdata->scan_delay_ms) - 1;
|
||||
scan_val |= (bits << KEYP_SCAN_PAUSE_SHIFT);
|
||||
|
||||
/* Row hold time is a multiple of 32KHz cycles. */
|
||||
cycles = (kp->pdata->row_hold_ns * KEYP_CLOCK_FREQ) / NSEC_PER_SEC;
|
||||
|
||||
scan_val |= (cycles << KEYP_SCAN_ROW_HOLD_SHIFT);
|
||||
|
||||
rc = pmic8xxx_kp_write_u8(kp, scan_val, KEYP_SCAN);
|
||||
if (rc)
|
||||
dev_err(kp->dev, "Error writing KEYP_SCAN reg, rc=%d\n", rc);
|
||||
|
||||
return rc;
|
||||
|
||||
}
|
||||
|
||||
static int __devinit pmic8xxx_kp_config_gpio(int gpio_start, int num_gpios,
|
||||
struct pmic8xxx_kp *kp, struct pm_gpio *gpio_config)
|
||||
{
|
||||
int rc, i;
|
||||
|
||||
if (gpio_start < 0 || num_gpios < 0)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < num_gpios; i++) {
|
||||
rc = pm8xxx_gpio_config(gpio_start + i, gpio_config);
|
||||
if (rc) {
|
||||
dev_err(kp->dev, "%s: FAIL pm8xxx_gpio_config():"
|
||||
"for PM GPIO [%d] rc=%d.\n",
|
||||
__func__, gpio_start + i, rc);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pmic8xxx_kp_enable(struct pmic8xxx_kp *kp)
|
||||
{
|
||||
int rc;
|
||||
|
||||
kp->ctrl_reg |= KEYP_CTRL_KEYP_EN;
|
||||
|
||||
rc = pmic8xxx_kp_write_u8(kp, kp->ctrl_reg, KEYP_CTRL);
|
||||
if (rc < 0)
|
||||
dev_err(kp->dev, "Error writing KEYP_CTRL reg, rc=%d\n", rc);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int pmic8xxx_kp_disable(struct pmic8xxx_kp *kp)
|
||||
{
|
||||
int rc;
|
||||
|
||||
kp->ctrl_reg &= ~KEYP_CTRL_KEYP_EN;
|
||||
|
||||
rc = pmic8xxx_kp_write_u8(kp, kp->ctrl_reg, KEYP_CTRL);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int pmic8xxx_kp_open(struct input_dev *dev)
|
||||
{
|
||||
struct pmic8xxx_kp *kp = input_get_drvdata(dev);
|
||||
|
||||
return pmic8xxx_kp_enable(kp);
|
||||
}
|
||||
|
||||
static void pmic8xxx_kp_close(struct input_dev *dev)
|
||||
{
|
||||
struct pmic8xxx_kp *kp = input_get_drvdata(dev);
|
||||
|
||||
pmic8xxx_kp_disable(kp);
|
||||
}
|
||||
|
||||
/*
|
||||
* keypad controller should be initialized in the following sequence
|
||||
* only, otherwise it might get into FSM stuck state.
|
||||
*
|
||||
* - Initialize keypad control parameters, like no. of rows, columns,
|
||||
* timing values etc.,
|
||||
* - configure rows and column gpios pull up/down.
|
||||
* - set irq edge type.
|
||||
* - enable the keypad controller.
|
||||
*/
|
||||
static int __devinit pmic8xxx_kp_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct pm8xxx_keypad_platform_data *pdata = mfd_get_data(pdev);
|
||||
const struct matrix_keymap_data *keymap_data;
|
||||
struct pmic8xxx_kp *kp;
|
||||
int rc;
|
||||
u8 ctrl_val;
|
||||
|
||||
struct pm_gpio kypd_drv = {
|
||||
.direction = PM_GPIO_DIR_OUT,
|
||||
.output_buffer = PM_GPIO_OUT_BUF_OPEN_DRAIN,
|
||||
.output_value = 0,
|
||||
.pull = PM_GPIO_PULL_NO,
|
||||
.vin_sel = PM_GPIO_VIN_S3,
|
||||
.out_strength = PM_GPIO_STRENGTH_LOW,
|
||||
.function = PM_GPIO_FUNC_1,
|
||||
.inv_int_pol = 1,
|
||||
};
|
||||
|
||||
struct pm_gpio kypd_sns = {
|
||||
.direction = PM_GPIO_DIR_IN,
|
||||
.pull = PM_GPIO_PULL_UP_31P5,
|
||||
.vin_sel = PM_GPIO_VIN_S3,
|
||||
.out_strength = PM_GPIO_STRENGTH_NO,
|
||||
.function = PM_GPIO_FUNC_NORMAL,
|
||||
.inv_int_pol = 1,
|
||||
};
|
||||
|
||||
|
||||
if (!pdata || !pdata->num_cols || !pdata->num_rows ||
|
||||
pdata->num_cols > PM8XXX_MAX_COLS ||
|
||||
pdata->num_rows > PM8XXX_MAX_ROWS ||
|
||||
pdata->num_cols < PM8XXX_MIN_COLS) {
|
||||
dev_err(&pdev->dev, "invalid platform data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!pdata->scan_delay_ms ||
|
||||
pdata->scan_delay_ms > MAX_SCAN_DELAY ||
|
||||
pdata->scan_delay_ms < MIN_SCAN_DELAY ||
|
||||
!is_power_of_2(pdata->scan_delay_ms)) {
|
||||
dev_err(&pdev->dev, "invalid keypad scan time supplied\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!pdata->row_hold_ns ||
|
||||
pdata->row_hold_ns > MAX_ROW_HOLD_DELAY ||
|
||||
pdata->row_hold_ns < MIN_ROW_HOLD_DELAY ||
|
||||
((pdata->row_hold_ns % MIN_ROW_HOLD_DELAY) != 0)) {
|
||||
dev_err(&pdev->dev, "invalid keypad row hold time supplied\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!pdata->debounce_ms ||
|
||||
((pdata->debounce_ms % 5) != 0) ||
|
||||
pdata->debounce_ms > MAX_DEBOUNCE_TIME ||
|
||||
pdata->debounce_ms < MIN_DEBOUNCE_TIME) {
|
||||
dev_err(&pdev->dev, "invalid debounce time supplied\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
keymap_data = pdata->keymap_data;
|
||||
if (!keymap_data) {
|
||||
dev_err(&pdev->dev, "no keymap data supplied\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
kp = kzalloc(sizeof(*kp), GFP_KERNEL);
|
||||
if (!kp)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(pdev, kp);
|
||||
|
||||
kp->pdata = pdata;
|
||||
kp->dev = &pdev->dev;
|
||||
|
||||
kp->input = input_allocate_device();
|
||||
if (!kp->input) {
|
||||
dev_err(&pdev->dev, "unable to allocate input device\n");
|
||||
rc = -ENOMEM;
|
||||
goto err_alloc_device;
|
||||
}
|
||||
|
||||
kp->key_sense_irq = platform_get_irq(pdev, 0);
|
||||
if (kp->key_sense_irq < 0) {
|
||||
dev_err(&pdev->dev, "unable to get keypad sense irq\n");
|
||||
rc = -ENXIO;
|
||||
goto err_get_irq;
|
||||
}
|
||||
|
||||
kp->key_stuck_irq = platform_get_irq(pdev, 1);
|
||||
if (kp->key_stuck_irq < 0) {
|
||||
dev_err(&pdev->dev, "unable to get keypad stuck irq\n");
|
||||
rc = -ENXIO;
|
||||
goto err_get_irq;
|
||||
}
|
||||
|
||||
kp->input->name = pdata->input_name ? : "PMIC8XXX keypad";
|
||||
kp->input->phys = pdata->input_phys_device ? : "pmic8xxx_keypad/input0";
|
||||
|
||||
kp->input->dev.parent = &pdev->dev;
|
||||
|
||||
kp->input->id.bustype = BUS_I2C;
|
||||
kp->input->id.version = 0x0001;
|
||||
kp->input->id.product = 0x0001;
|
||||
kp->input->id.vendor = 0x0001;
|
||||
|
||||
kp->input->evbit[0] = BIT_MASK(EV_KEY);
|
||||
|
||||
if (pdata->rep)
|
||||
__set_bit(EV_REP, kp->input->evbit);
|
||||
|
||||
kp->input->keycode = kp->keycodes;
|
||||
kp->input->keycodemax = PM8XXX_MATRIX_MAX_SIZE;
|
||||
kp->input->keycodesize = sizeof(kp->keycodes);
|
||||
kp->input->open = pmic8xxx_kp_open;
|
||||
kp->input->close = pmic8xxx_kp_close;
|
||||
|
||||
matrix_keypad_build_keymap(keymap_data, PM8XXX_ROW_SHIFT,
|
||||
kp->input->keycode, kp->input->keybit);
|
||||
|
||||
input_set_capability(kp->input, EV_MSC, MSC_SCAN);
|
||||
input_set_drvdata(kp->input, kp);
|
||||
|
||||
/* initialize keypad state */
|
||||
memset(kp->keystate, 0xff, sizeof(kp->keystate));
|
||||
memset(kp->stuckstate, 0xff, sizeof(kp->stuckstate));
|
||||
|
||||
rc = pmic8xxx_kpd_init(kp);
|
||||
if (rc < 0) {
|
||||
dev_err(&pdev->dev, "unable to initialize keypad controller\n");
|
||||
goto err_get_irq;
|
||||
}
|
||||
|
||||
rc = pmic8xxx_kp_config_gpio(pdata->cols_gpio_start,
|
||||
pdata->num_cols, kp, &kypd_sns);
|
||||
if (rc < 0) {
|
||||
dev_err(&pdev->dev, "unable to configure keypad sense lines\n");
|
||||
goto err_gpio_config;
|
||||
}
|
||||
|
||||
rc = pmic8xxx_kp_config_gpio(pdata->rows_gpio_start,
|
||||
pdata->num_rows, kp, &kypd_drv);
|
||||
if (rc < 0) {
|
||||
dev_err(&pdev->dev, "unable to configure keypad drive lines\n");
|
||||
goto err_gpio_config;
|
||||
}
|
||||
|
||||
rc = request_any_context_irq(kp->key_sense_irq, pmic8xxx_kp_irq,
|
||||
IRQF_TRIGGER_RISING, "pmic-keypad", kp);
|
||||
if (rc < 0) {
|
||||
dev_err(&pdev->dev, "failed to request keypad sense irq\n");
|
||||
goto err_get_irq;
|
||||
}
|
||||
|
||||
rc = request_any_context_irq(kp->key_stuck_irq, pmic8xxx_kp_stuck_irq,
|
||||
IRQF_TRIGGER_RISING, "pmic-keypad-stuck", kp);
|
||||
if (rc < 0) {
|
||||
dev_err(&pdev->dev, "failed to request keypad stuck irq\n");
|
||||
goto err_req_stuck_irq;
|
||||
}
|
||||
|
||||
rc = pmic8xxx_kp_read_u8(kp, &ctrl_val, KEYP_CTRL);
|
||||
if (rc < 0) {
|
||||
dev_err(&pdev->dev, "failed to read KEYP_CTRL register\n");
|
||||
goto err_pmic_reg_read;
|
||||
}
|
||||
|
||||
kp->ctrl_reg = ctrl_val;
|
||||
|
||||
rc = input_register_device(kp->input);
|
||||
if (rc < 0) {
|
||||
dev_err(&pdev->dev, "unable to register keypad input device\n");
|
||||
goto err_pmic_reg_read;
|
||||
}
|
||||
|
||||
device_init_wakeup(&pdev->dev, pdata->wakeup);
|
||||
|
||||
return 0;
|
||||
|
||||
err_pmic_reg_read:
|
||||
free_irq(kp->key_stuck_irq, NULL);
|
||||
err_req_stuck_irq:
|
||||
free_irq(kp->key_sense_irq, NULL);
|
||||
err_gpio_config:
|
||||
err_get_irq:
|
||||
input_free_device(kp->input);
|
||||
err_alloc_device:
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
kfree(kp);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int __devexit pmic8xxx_kp_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct pmic8xxx_kp *kp = platform_get_drvdata(pdev);
|
||||
|
||||
device_init_wakeup(&pdev->dev, 0);
|
||||
free_irq(kp->key_stuck_irq, NULL);
|
||||
free_irq(kp->key_sense_irq, NULL);
|
||||
input_unregister_device(kp->input);
|
||||
kfree(kp);
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int pmic8xxx_kp_suspend(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct pmic8xxx_kp *kp = platform_get_drvdata(pdev);
|
||||
struct input_dev *input_dev = kp->input;
|
||||
|
||||
if (device_may_wakeup(dev)) {
|
||||
enable_irq_wake(kp->key_sense_irq);
|
||||
} else {
|
||||
mutex_lock(&input_dev->mutex);
|
||||
|
||||
if (input_dev->users)
|
||||
pmic8xxx_kp_disable(kp);
|
||||
|
||||
mutex_unlock(&input_dev->mutex);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pmic8xxx_kp_resume(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct pmic8xxx_kp *kp = platform_get_drvdata(pdev);
|
||||
struct input_dev *input_dev = kp->input;
|
||||
|
||||
if (device_may_wakeup(dev)) {
|
||||
disable_irq_wake(kp->key_sense_irq);
|
||||
} else {
|
||||
mutex_lock(&input_dev->mutex);
|
||||
|
||||
if (input_dev->users)
|
||||
pmic8xxx_kp_enable(kp);
|
||||
|
||||
mutex_unlock(&input_dev->mutex);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(pm8xxx_kp_pm_ops,
|
||||
pmic8xxx_kp_suspend, pmic8xxx_kp_resume);
|
||||
|
||||
static struct platform_driver pmic8xxx_kp_driver = {
|
||||
.probe = pmic8xxx_kp_probe,
|
||||
.remove = __devexit_p(pmic8xxx_kp_remove),
|
||||
.driver = {
|
||||
.name = PM8XXX_KEYPAD_DEV_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &pm8xxx_kp_pm_ops,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init pmic8xxx_kp_init(void)
|
||||
{
|
||||
return platform_driver_register(&pmic8xxx_kp_driver);
|
||||
}
|
||||
module_init(pmic8xxx_kp_init);
|
||||
|
||||
static void __exit pmic8xxx_kp_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&pmic8xxx_kp_driver);
|
||||
}
|
||||
module_exit(pmic8xxx_kp_exit);
|
||||
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_DESCRIPTION("PMIC8XXX keypad driver");
|
||||
MODULE_VERSION("1.0");
|
||||
MODULE_ALIAS("platform:pmic8xxx_keypad");
|
||||
MODULE_AUTHOR("Trilok Soni <tsoni@codeaurora.org>");
|
@ -330,6 +330,17 @@ config INPUT_PWM_BEEPER
|
||||
To compile this driver as a module, choose M here: the module will be
|
||||
called pwm-beeper.
|
||||
|
||||
config INPUT_PMIC8XXX_PWRKEY
|
||||
tristate "PMIC8XXX power key support"
|
||||
depends on MFD_PM8XXX
|
||||
help
|
||||
Say Y here if you want support for the PMIC8XXX power key.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called pmic8xxx-pwrkey.
|
||||
|
||||
config INPUT_GPIO_ROTARY_ENCODER
|
||||
tristate "Rotary encoders connected to GPIO pins"
|
||||
depends on GPIOLIB && GENERIC_GPIO
|
||||
|
@ -33,6 +33,7 @@ obj-$(CONFIG_INPUT_PCF8574) += pcf8574_keypad.o
|
||||
obj-$(CONFIG_INPUT_PCSPKR) += pcspkr.o
|
||||
obj-$(CONFIG_INPUT_POWERMATE) += powermate.o
|
||||
obj-$(CONFIG_INPUT_PWM_BEEPER) += pwm-beeper.o
|
||||
obj-$(CONFIG_INPUT_PMIC8XXX_PWRKEY) += pmic8xxx-pwrkey.o
|
||||
obj-$(CONFIG_INPUT_RB532_BUTTON) += rb532_button.o
|
||||
obj-$(CONFIG_INPUT_GPIO_ROTARY_ENCODER) += rotary_encoder.o
|
||||
obj-$(CONFIG_INPUT_SGI_BTNS) += sgi_btns.o
|
||||
|
231
drivers/input/misc/pmic8xxx-pwrkey.c
Normal file
231
drivers/input/misc/pmic8xxx-pwrkey.c
Normal file
@ -0,0 +1,231 @@
|
||||
/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/log2.h>
|
||||
|
||||
#include <linux/mfd/pm8xxx/core.h>
|
||||
#include <linux/input/pmic8xxx-pwrkey.h>
|
||||
|
||||
#define PON_CNTL_1 0x1C
|
||||
#define PON_CNTL_PULL_UP BIT(7)
|
||||
#define PON_CNTL_TRIG_DELAY_MASK (0x7)
|
||||
|
||||
/**
|
||||
* struct pmic8xxx_pwrkey - pmic8xxx pwrkey information
|
||||
* @key_press_irq: key press irq number
|
||||
*/
|
||||
struct pmic8xxx_pwrkey {
|
||||
struct input_dev *pwr;
|
||||
int key_press_irq;
|
||||
};
|
||||
|
||||
static irqreturn_t pwrkey_press_irq(int irq, void *_pwrkey)
|
||||
{
|
||||
struct pmic8xxx_pwrkey *pwrkey = _pwrkey;
|
||||
|
||||
input_report_key(pwrkey->pwr, KEY_POWER, 1);
|
||||
input_sync(pwrkey->pwr);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t pwrkey_release_irq(int irq, void *_pwrkey)
|
||||
{
|
||||
struct pmic8xxx_pwrkey *pwrkey = _pwrkey;
|
||||
|
||||
input_report_key(pwrkey->pwr, KEY_POWER, 0);
|
||||
input_sync(pwrkey->pwr);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int pmic8xxx_pwrkey_suspend(struct device *dev)
|
||||
{
|
||||
struct pmic8xxx_pwrkey *pwrkey = dev_get_drvdata(dev);
|
||||
|
||||
if (device_may_wakeup(dev))
|
||||
enable_irq_wake(pwrkey->key_press_irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pmic8xxx_pwrkey_resume(struct device *dev)
|
||||
{
|
||||
struct pmic8xxx_pwrkey *pwrkey = dev_get_drvdata(dev);
|
||||
|
||||
if (device_may_wakeup(dev))
|
||||
disable_irq_wake(pwrkey->key_press_irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(pm8xxx_pwr_key_pm_ops,
|
||||
pmic8xxx_pwrkey_suspend, pmic8xxx_pwrkey_resume);
|
||||
|
||||
static int __devinit pmic8xxx_pwrkey_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct input_dev *pwr;
|
||||
int key_release_irq = platform_get_irq(pdev, 0);
|
||||
int key_press_irq = platform_get_irq(pdev, 1);
|
||||
int err;
|
||||
unsigned int delay;
|
||||
u8 pon_cntl;
|
||||
struct pmic8xxx_pwrkey *pwrkey;
|
||||
const struct pm8xxx_pwrkey_platform_data *pdata = mfd_get_data(pdev);
|
||||
|
||||
if (!pdata) {
|
||||
dev_err(&pdev->dev, "power key platform data not supplied\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (pdata->kpd_trigger_delay_us > 62500) {
|
||||
dev_err(&pdev->dev, "invalid power key trigger delay\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pwrkey = kzalloc(sizeof(*pwrkey), GFP_KERNEL);
|
||||
if (!pwrkey)
|
||||
return -ENOMEM;
|
||||
|
||||
pwr = input_allocate_device();
|
||||
if (!pwr) {
|
||||
dev_dbg(&pdev->dev, "Can't allocate power button\n");
|
||||
err = -ENOMEM;
|
||||
goto free_pwrkey;
|
||||
}
|
||||
|
||||
input_set_capability(pwr, EV_KEY, KEY_POWER);
|
||||
|
||||
pwr->name = "pmic8xxx_pwrkey";
|
||||
pwr->phys = "pmic8xxx_pwrkey/input0";
|
||||
pwr->dev.parent = &pdev->dev;
|
||||
|
||||
delay = (pdata->kpd_trigger_delay_us << 10) / USEC_PER_SEC;
|
||||
delay = 1 + ilog2(delay);
|
||||
|
||||
err = pm8xxx_readb(pdev->dev.parent, PON_CNTL_1, &pon_cntl);
|
||||
if (err < 0) {
|
||||
dev_err(&pdev->dev, "failed reading PON_CNTL_1 err=%d\n", err);
|
||||
goto free_input_dev;
|
||||
}
|
||||
|
||||
pon_cntl &= ~PON_CNTL_TRIG_DELAY_MASK;
|
||||
pon_cntl |= (delay & PON_CNTL_TRIG_DELAY_MASK);
|
||||
if (pdata->pull_up)
|
||||
pon_cntl |= PON_CNTL_PULL_UP;
|
||||
else
|
||||
pon_cntl &= ~PON_CNTL_PULL_UP;
|
||||
|
||||
err = pm8xxx_writeb(pdev->dev.parent, PON_CNTL_1, pon_cntl);
|
||||
if (err < 0) {
|
||||
dev_err(&pdev->dev, "failed writing PON_CNTL_1 err=%d\n", err);
|
||||
goto free_input_dev;
|
||||
}
|
||||
|
||||
err = input_register_device(pwr);
|
||||
if (err) {
|
||||
dev_dbg(&pdev->dev, "Can't register power key: %d\n", err);
|
||||
goto free_input_dev;
|
||||
}
|
||||
|
||||
pwrkey->key_press_irq = key_press_irq;
|
||||
pwrkey->pwr = pwr;
|
||||
|
||||
platform_set_drvdata(pdev, pwrkey);
|
||||
|
||||
err = request_irq(key_press_irq, pwrkey_press_irq,
|
||||
IRQF_TRIGGER_RISING, "pmic8xxx_pwrkey_press", pwrkey);
|
||||
if (err < 0) {
|
||||
dev_dbg(&pdev->dev, "Can't get %d IRQ for pwrkey: %d\n",
|
||||
key_press_irq, err);
|
||||
goto unreg_input_dev;
|
||||
}
|
||||
|
||||
err = request_irq(key_release_irq, pwrkey_release_irq,
|
||||
IRQF_TRIGGER_RISING, "pmic8xxx_pwrkey_release", pwrkey);
|
||||
if (err < 0) {
|
||||
dev_dbg(&pdev->dev, "Can't get %d IRQ for pwrkey: %d\n",
|
||||
key_release_irq, err);
|
||||
|
||||
goto free_press_irq;
|
||||
}
|
||||
|
||||
device_init_wakeup(&pdev->dev, pdata->wakeup);
|
||||
|
||||
return 0;
|
||||
|
||||
free_press_irq:
|
||||
free_irq(key_press_irq, NULL);
|
||||
unreg_input_dev:
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
input_unregister_device(pwr);
|
||||
pwr = NULL;
|
||||
free_input_dev:
|
||||
input_free_device(pwr);
|
||||
free_pwrkey:
|
||||
kfree(pwrkey);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __devexit pmic8xxx_pwrkey_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct pmic8xxx_pwrkey *pwrkey = platform_get_drvdata(pdev);
|
||||
int key_release_irq = platform_get_irq(pdev, 0);
|
||||
int key_press_irq = platform_get_irq(pdev, 1);
|
||||
|
||||
device_init_wakeup(&pdev->dev, 0);
|
||||
|
||||
free_irq(key_press_irq, pwrkey);
|
||||
free_irq(key_release_irq, pwrkey);
|
||||
input_unregister_device(pwrkey->pwr);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
kfree(pwrkey);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver pmic8xxx_pwrkey_driver = {
|
||||
.probe = pmic8xxx_pwrkey_probe,
|
||||
.remove = __devexit_p(pmic8xxx_pwrkey_remove),
|
||||
.driver = {
|
||||
.name = PM8XXX_PWRKEY_DEV_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &pm8xxx_pwr_key_pm_ops,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init pmic8xxx_pwrkey_init(void)
|
||||
{
|
||||
return platform_driver_register(&pmic8xxx_pwrkey_driver);
|
||||
}
|
||||
module_init(pmic8xxx_pwrkey_init);
|
||||
|
||||
static void __exit pmic8xxx_pwrkey_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&pmic8xxx_pwrkey_driver);
|
||||
}
|
||||
module_exit(pmic8xxx_pwrkey_exit);
|
||||
|
||||
MODULE_ALIAS("platform:pmic8xxx_pwrkey");
|
||||
MODULE_DESCRIPTION("PMIC8XXX Power Key driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_AUTHOR("Trilok Soni <tsoni@codeaurora.org>");
|
@ -29,7 +29,6 @@
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/i2c/twl.h>
|
||||
#include <linux/mfd/twl4030-codec.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
@ -197,7 +196,7 @@ static SIMPLE_DEV_PM_OPS(twl4030_vibra_pm_ops,
|
||||
|
||||
static int __devinit twl4030_vibra_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct twl4030_codec_vibra_data *pdata = mfd_get_data(pdev);
|
||||
struct twl4030_codec_vibra_data *pdata = pdev->dev.platform_data;
|
||||
struct vibra_info *info;
|
||||
int ret;
|
||||
|
||||
|
@ -389,6 +389,16 @@ config LEDS_NETXBIG
|
||||
and 5Big Network v2 boards. The LEDs are wired to a CPLD and are
|
||||
controlled through a GPIO extension bus.
|
||||
|
||||
config LEDS_ASIC3
|
||||
bool "LED support for the HTC ASIC3"
|
||||
depends on MFD_ASIC3
|
||||
default y
|
||||
help
|
||||
This option enables support for the LEDs on the HTC ASIC3. The HTC
|
||||
ASIC3 LED GPIOs are inputs, not outputs, thus the leds-gpio driver
|
||||
cannot be used. This driver supports hardware blinking with an on+off
|
||||
period from 62ms to 125s. Say Y to enable LEDs on the HP iPAQ hx4700.
|
||||
|
||||
config LEDS_TRIGGERS
|
||||
bool "LED Trigger support"
|
||||
depends on LEDS_CLASS
|
||||
|
@ -42,6 +42,7 @@ obj-$(CONFIG_LEDS_DELL_NETBOOKS) += dell-led.o
|
||||
obj-$(CONFIG_LEDS_MC13783) += leds-mc13783.o
|
||||
obj-$(CONFIG_LEDS_NS2) += leds-ns2.o
|
||||
obj-$(CONFIG_LEDS_NETXBIG) += leds-netxbig.o
|
||||
obj-$(CONFIG_LEDS_ASIC3) += leds-asic3.o
|
||||
|
||||
# LED SPI Drivers
|
||||
obj-$(CONFIG_LEDS_DAC124S085) += leds-dac124s085.o
|
||||
|
@ -17,7 +17,6 @@
|
||||
#include <linux/leds.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/88pm860x.h>
|
||||
|
||||
#define LED_PWM_SHIFT (3)
|
||||
@ -171,7 +170,6 @@ static int pm860x_led_probe(struct platform_device *pdev)
|
||||
struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
|
||||
struct pm860x_led_pdata *pdata;
|
||||
struct pm860x_led *data;
|
||||
struct mfd_cell *cell;
|
||||
struct resource *res;
|
||||
int ret;
|
||||
|
||||
@ -181,10 +179,7 @@ static int pm860x_led_probe(struct platform_device *pdev)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cell = pdev->dev.platform_data;
|
||||
if (cell == NULL)
|
||||
return -ENODEV;
|
||||
pdata = cell->mfd_data;
|
||||
pdata = pdev->dev.platform_data;
|
||||
if (pdata == NULL) {
|
||||
dev_err(&pdev->dev, "No platform data!\n");
|
||||
return -EINVAL;
|
||||
|
165
drivers/leds/leds-asic3.c
Normal file
165
drivers/leds/leds-asic3.c
Normal file
@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Paul Parsons <lost.distance@yahoo.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/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <linux/mfd/asic3.h>
|
||||
#include <linux/mfd/core.h>
|
||||
|
||||
/*
|
||||
* The HTC ASIC3 LED GPIOs are inputs, not outputs.
|
||||
* Hence we turn the LEDs on/off via the TimeBase register.
|
||||
*/
|
||||
|
||||
/*
|
||||
* When TimeBase is 4 the clock resolution is about 32Hz.
|
||||
* This driver supports hardware blinking with an on+off
|
||||
* period from 62ms (2 clocks) to 125s (4000 clocks).
|
||||
*/
|
||||
#define MS_TO_CLK(ms) DIV_ROUND_CLOSEST(((ms)*1024), 32000)
|
||||
#define CLK_TO_MS(clk) (((clk)*32000)/1024)
|
||||
#define MAX_CLK 4000 /* Fits into 12-bit Time registers */
|
||||
#define MAX_MS CLK_TO_MS(MAX_CLK)
|
||||
|
||||
static const unsigned int led_n_base[ASIC3_NUM_LEDS] = {
|
||||
[0] = ASIC3_LED_0_Base,
|
||||
[1] = ASIC3_LED_1_Base,
|
||||
[2] = ASIC3_LED_2_Base,
|
||||
};
|
||||
|
||||
static void brightness_set(struct led_classdev *cdev,
|
||||
enum led_brightness value)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(cdev->dev->parent);
|
||||
const struct mfd_cell *cell = mfd_get_cell(pdev);
|
||||
struct asic3 *asic = dev_get_drvdata(pdev->dev.parent);
|
||||
u32 timebase;
|
||||
unsigned int base;
|
||||
|
||||
timebase = (value == LED_OFF) ? 0 : (LED_EN|0x4);
|
||||
|
||||
base = led_n_base[cell->id];
|
||||
asic3_write_register(asic, (base + ASIC3_LED_PeriodTime), 32);
|
||||
asic3_write_register(asic, (base + ASIC3_LED_DutyTime), 32);
|
||||
asic3_write_register(asic, (base + ASIC3_LED_AutoStopCount), 0);
|
||||
asic3_write_register(asic, (base + ASIC3_LED_TimeBase), timebase);
|
||||
}
|
||||
|
||||
static int blink_set(struct led_classdev *cdev,
|
||||
unsigned long *delay_on,
|
||||
unsigned long *delay_off)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(cdev->dev->parent);
|
||||
const struct mfd_cell *cell = mfd_get_cell(pdev);
|
||||
struct asic3 *asic = dev_get_drvdata(pdev->dev.parent);
|
||||
u32 on;
|
||||
u32 off;
|
||||
unsigned int base;
|
||||
|
||||
if (*delay_on > MAX_MS || *delay_off > MAX_MS)
|
||||
return -EINVAL;
|
||||
|
||||
if (*delay_on == 0 && *delay_off == 0) {
|
||||
/* If both are zero then a sensible default should be chosen */
|
||||
on = MS_TO_CLK(500);
|
||||
off = MS_TO_CLK(500);
|
||||
} else {
|
||||
on = MS_TO_CLK(*delay_on);
|
||||
off = MS_TO_CLK(*delay_off);
|
||||
if ((on + off) > MAX_CLK)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
base = led_n_base[cell->id];
|
||||
asic3_write_register(asic, (base + ASIC3_LED_PeriodTime), (on + off));
|
||||
asic3_write_register(asic, (base + ASIC3_LED_DutyTime), on);
|
||||
asic3_write_register(asic, (base + ASIC3_LED_AutoStopCount), 0);
|
||||
asic3_write_register(asic, (base + ASIC3_LED_TimeBase), (LED_EN|0x4));
|
||||
|
||||
*delay_on = CLK_TO_MS(on);
|
||||
*delay_off = CLK_TO_MS(off);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devinit asic3_led_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct asic3_led *led = pdev->dev.platform_data;
|
||||
int ret;
|
||||
|
||||
ret = mfd_cell_enable(pdev);
|
||||
if (ret < 0)
|
||||
goto ret0;
|
||||
|
||||
led->cdev = kzalloc(sizeof(struct led_classdev), GFP_KERNEL);
|
||||
if (!led->cdev) {
|
||||
ret = -ENOMEM;
|
||||
goto ret1;
|
||||
}
|
||||
|
||||
led->cdev->name = led->name;
|
||||
led->cdev->default_trigger = led->default_trigger;
|
||||
led->cdev->brightness_set = brightness_set;
|
||||
led->cdev->blink_set = blink_set;
|
||||
|
||||
ret = led_classdev_register(&pdev->dev, led->cdev);
|
||||
if (ret < 0)
|
||||
goto ret2;
|
||||
|
||||
return 0;
|
||||
|
||||
ret2:
|
||||
kfree(led->cdev);
|
||||
ret1:
|
||||
(void) mfd_cell_disable(pdev);
|
||||
ret0:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit asic3_led_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct asic3_led *led = pdev->dev.platform_data;
|
||||
|
||||
led_classdev_unregister(led->cdev);
|
||||
|
||||
kfree(led->cdev);
|
||||
|
||||
return mfd_cell_disable(pdev);
|
||||
}
|
||||
|
||||
static struct platform_driver asic3_led_driver = {
|
||||
.probe = asic3_led_probe,
|
||||
.remove = __devexit_p(asic3_led_remove),
|
||||
.driver = {
|
||||
.name = "leds-asic3",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
MODULE_ALIAS("platform:leds-asic3");
|
||||
|
||||
static int __init asic3_led_init(void)
|
||||
{
|
||||
return platform_driver_register(&asic3_led_driver);
|
||||
}
|
||||
|
||||
static void __exit asic3_led_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&asic3_led_driver);
|
||||
}
|
||||
|
||||
module_init(asic3_led_init);
|
||||
module_exit(asic3_led_exit);
|
||||
|
||||
MODULE_AUTHOR("Paul Parsons <lost.distance@yahoo.com>");
|
||||
MODULE_DESCRIPTION("HTC ASIC3 LED driver");
|
||||
MODULE_LICENSE("GPL");
|
@ -22,7 +22,6 @@
|
||||
#include <linux/leds.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/mfd/mc13783.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
struct mc13783_led {
|
||||
@ -184,7 +183,7 @@ static int __devinit mc13783_led_setup(struct mc13783_led *led, int max_current)
|
||||
|
||||
static int __devinit mc13783_leds_prepare(struct platform_device *pdev)
|
||||
{
|
||||
struct mc13783_leds_platform_data *pdata = mfd_get_data(pdev);
|
||||
struct mc13783_leds_platform_data *pdata = dev_get_platdata(&pdev->dev);
|
||||
struct mc13783 *dev = dev_get_drvdata(pdev->dev.parent);
|
||||
int ret = 0;
|
||||
int reg = 0;
|
||||
@ -265,7 +264,7 @@ out:
|
||||
|
||||
static int __devinit mc13783_led_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct mc13783_leds_platform_data *pdata = mfd_get_data(pdev);
|
||||
struct mc13783_leds_platform_data *pdata = dev_get_platdata(&pdev->dev);
|
||||
struct mc13783_led_platform_data *led_cur;
|
||||
struct mc13783_led *led, *led_dat;
|
||||
int ret, i;
|
||||
@ -352,7 +351,7 @@ err_free:
|
||||
|
||||
static int __devexit mc13783_led_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct mc13783_leds_platform_data *pdata = mfd_get_data(pdev);
|
||||
struct mc13783_leds_platform_data *pdata = dev_get_platdata(&pdev->dev);
|
||||
struct mc13783_led *led = platform_get_drvdata(pdev);
|
||||
struct mc13783 *dev = dev_get_drvdata(pdev->dev.parent);
|
||||
int i;
|
||||
|
@ -21,7 +21,6 @@
|
||||
#include <media/v4l2-ioctl.h>
|
||||
#include <media/v4l2-device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/i2c.h>
|
||||
@ -149,7 +148,7 @@ static const struct v4l2_file_operations timbradio_fops = {
|
||||
|
||||
static int __devinit timbradio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct timb_radio_platform_data *pdata = mfd_get_data(pdev);
|
||||
struct timb_radio_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct timbradio *tr;
|
||||
int err;
|
||||
|
||||
|
@ -1990,7 +1990,7 @@ static int wl1273_fm_radio_remove(struct platform_device *pdev)
|
||||
|
||||
static int __devinit wl1273_fm_radio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct wl1273_core **core = mfd_get_data(pdev);
|
||||
struct wl1273_core **core = pdev->dev.platform_data;
|
||||
struct wl1273_device *radio;
|
||||
struct v4l2_ctrl *ctrl;
|
||||
int r = 0;
|
||||
|
@ -24,7 +24,6 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/dmaengine.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/list.h>
|
||||
@ -791,7 +790,7 @@ static int __devinit timblogiw_probe(struct platform_device *pdev)
|
||||
{
|
||||
int err;
|
||||
struct timblogiw *lw = NULL;
|
||||
struct timb_video_platform_data *pdata = mfd_get_data(pdev);
|
||||
struct timb_video_platform_data *pdata = pdev->dev.platform_data;
|
||||
|
||||
if (!pdata) {
|
||||
dev_err(&pdev->dev, "No platform data\n");
|
||||
|
@ -21,13 +21,13 @@
|
||||
|
||||
#define INT_STATUS_NUM 3
|
||||
|
||||
static struct resource bk_resources[] __initdata = {
|
||||
static struct resource bk_resources[] __devinitdata = {
|
||||
{PM8606_BACKLIGHT1, PM8606_BACKLIGHT1, "backlight-0", IORESOURCE_IO,},
|
||||
{PM8606_BACKLIGHT2, PM8606_BACKLIGHT2, "backlight-1", IORESOURCE_IO,},
|
||||
{PM8606_BACKLIGHT3, PM8606_BACKLIGHT3, "backlight-2", IORESOURCE_IO,},
|
||||
};
|
||||
|
||||
static struct resource led_resources[] __initdata = {
|
||||
static struct resource led_resources[] __devinitdata = {
|
||||
{PM8606_LED1_RED, PM8606_LED1_RED, "led0-red", IORESOURCE_IO,},
|
||||
{PM8606_LED1_GREEN, PM8606_LED1_GREEN, "led0-green", IORESOURCE_IO,},
|
||||
{PM8606_LED1_BLUE, PM8606_LED1_BLUE, "led0-blue", IORESOURCE_IO,},
|
||||
@ -36,7 +36,7 @@ static struct resource led_resources[] __initdata = {
|
||||
{PM8606_LED2_BLUE, PM8606_LED2_BLUE, "led1-blue", IORESOURCE_IO,},
|
||||
};
|
||||
|
||||
static struct resource regulator_resources[] __initdata = {
|
||||
static struct resource regulator_resources[] __devinitdata = {
|
||||
{PM8607_ID_BUCK1, PM8607_ID_BUCK1, "buck-1", IORESOURCE_IO,},
|
||||
{PM8607_ID_BUCK2, PM8607_ID_BUCK2, "buck-2", IORESOURCE_IO,},
|
||||
{PM8607_ID_BUCK3, PM8607_ID_BUCK3, "buck-3", IORESOURCE_IO,},
|
||||
@ -57,15 +57,15 @@ static struct resource regulator_resources[] __initdata = {
|
||||
{PM8607_ID_LDO15, PM8607_ID_LDO15, "ldo-15", IORESOURCE_IO,},
|
||||
};
|
||||
|
||||
static struct resource touch_resources[] __initdata = {
|
||||
static struct resource touch_resources[] __devinitdata = {
|
||||
{PM8607_IRQ_PEN, PM8607_IRQ_PEN, "touch", IORESOURCE_IRQ,},
|
||||
};
|
||||
|
||||
static struct resource onkey_resources[] __initdata = {
|
||||
static struct resource onkey_resources[] __devinitdata = {
|
||||
{PM8607_IRQ_ONKEY, PM8607_IRQ_ONKEY, "onkey", IORESOURCE_IRQ,},
|
||||
};
|
||||
|
||||
static struct resource codec_resources[] __initdata = {
|
||||
static struct resource codec_resources[] __devinitdata = {
|
||||
/* Headset microphone insertion or removal */
|
||||
{PM8607_IRQ_MICIN, PM8607_IRQ_MICIN, "micin", IORESOURCE_IRQ,},
|
||||
/* Hook-switch press or release */
|
||||
@ -76,12 +76,12 @@ static struct resource codec_resources[] __initdata = {
|
||||
{PM8607_IRQ_AUDIO_SHORT, PM8607_IRQ_AUDIO_SHORT, "audio-short", IORESOURCE_IRQ,},
|
||||
};
|
||||
|
||||
static struct resource battery_resources[] __initdata = {
|
||||
static struct resource battery_resources[] __devinitdata = {
|
||||
{PM8607_IRQ_CC, PM8607_IRQ_CC, "columb counter", IORESOURCE_IRQ,},
|
||||
{PM8607_IRQ_BAT, PM8607_IRQ_BAT, "battery", IORESOURCE_IRQ,},
|
||||
};
|
||||
|
||||
static struct resource charger_resources[] __initdata = {
|
||||
static struct resource charger_resources[] __devinitdata = {
|
||||
{PM8607_IRQ_CHG, PM8607_IRQ_CHG, "charger detect", IORESOURCE_IRQ,},
|
||||
{PM8607_IRQ_CHG_DONE, PM8607_IRQ_CHG_DONE, "charging done", IORESOURCE_IRQ,},
|
||||
{PM8607_IRQ_CHG_FAULT, PM8607_IRQ_CHG_FAULT, "charging timeout", IORESOURCE_IRQ,},
|
||||
@ -90,13 +90,17 @@ static struct resource charger_resources[] __initdata = {
|
||||
{PM8607_IRQ_VCHG, PM8607_IRQ_VCHG, "vchg voltage", IORESOURCE_IRQ,},
|
||||
};
|
||||
|
||||
static struct mfd_cell bk_devs[] __initdata = {
|
||||
static struct resource rtc_resources[] __devinitdata = {
|
||||
{PM8607_IRQ_RTC, PM8607_IRQ_RTC, "rtc", IORESOURCE_IRQ,},
|
||||
};
|
||||
|
||||
static struct mfd_cell bk_devs[] = {
|
||||
{"88pm860x-backlight", 0,},
|
||||
{"88pm860x-backlight", 1,},
|
||||
{"88pm860x-backlight", 2,},
|
||||
};
|
||||
|
||||
static struct mfd_cell led_devs[] __initdata = {
|
||||
static struct mfd_cell led_devs[] = {
|
||||
{"88pm860x-led", 0,},
|
||||
{"88pm860x-led", 1,},
|
||||
{"88pm860x-led", 2,},
|
||||
@ -105,7 +109,7 @@ static struct mfd_cell led_devs[] __initdata = {
|
||||
{"88pm860x-led", 5,},
|
||||
};
|
||||
|
||||
static struct mfd_cell regulator_devs[] __initdata = {
|
||||
static struct mfd_cell regulator_devs[] = {
|
||||
{"88pm860x-regulator", 0,},
|
||||
{"88pm860x-regulator", 1,},
|
||||
{"88pm860x-regulator", 2,},
|
||||
@ -126,15 +130,15 @@ static struct mfd_cell regulator_devs[] __initdata = {
|
||||
{"88pm860x-regulator", 17,},
|
||||
};
|
||||
|
||||
static struct mfd_cell touch_devs[] __initdata = {
|
||||
static struct mfd_cell touch_devs[] = {
|
||||
{"88pm860x-touch", -1,},
|
||||
};
|
||||
|
||||
static struct mfd_cell onkey_devs[] __initdata = {
|
||||
static struct mfd_cell onkey_devs[] = {
|
||||
{"88pm860x-onkey", -1,},
|
||||
};
|
||||
|
||||
static struct mfd_cell codec_devs[] __initdata = {
|
||||
static struct mfd_cell codec_devs[] = {
|
||||
{"88pm860x-codec", -1,},
|
||||
};
|
||||
|
||||
@ -143,11 +147,10 @@ static struct mfd_cell power_devs[] = {
|
||||
{"88pm860x-charger", -1,},
|
||||
};
|
||||
|
||||
static struct pm860x_backlight_pdata bk_pdata[ARRAY_SIZE(bk_devs)];
|
||||
static struct pm860x_led_pdata led_pdata[ARRAY_SIZE(led_devs)];
|
||||
static struct regulator_init_data regulator_pdata[ARRAY_SIZE(regulator_devs)];
|
||||
static struct pm860x_touch_pdata touch_pdata;
|
||||
static struct pm860x_power_pdata power_pdata;
|
||||
static struct mfd_cell rtc_devs[] = {
|
||||
{"88pm860x-rtc", -1,},
|
||||
};
|
||||
|
||||
|
||||
struct pm860x_irq_data {
|
||||
int reg;
|
||||
@ -501,7 +504,6 @@ static void device_irq_exit(struct pm860x_chip *chip)
|
||||
}
|
||||
|
||||
static void __devinit device_bk_init(struct pm860x_chip *chip,
|
||||
struct i2c_client *i2c,
|
||||
struct pm860x_platform_data *pdata)
|
||||
{
|
||||
int ret;
|
||||
@ -514,13 +516,12 @@ static void __devinit device_bk_init(struct pm860x_chip *chip,
|
||||
pdata->num_backlights = ARRAY_SIZE(bk_devs);
|
||||
|
||||
for (i = 0; i < pdata->num_backlights; i++) {
|
||||
memcpy(&bk_pdata[i], &pdata->backlight[i],
|
||||
sizeof(struct pm860x_backlight_pdata));
|
||||
bk_devs[i].mfd_data = &bk_pdata[i];
|
||||
bk_devs[i].platform_data = &pdata->backlight[i];
|
||||
bk_devs[i].pdata_size = sizeof(struct pm860x_backlight_pdata);
|
||||
|
||||
for (j = 0; j < ARRAY_SIZE(bk_devs); j++) {
|
||||
id = bk_resources[j].start;
|
||||
if (bk_pdata[i].flags != id)
|
||||
if (pdata->backlight[i].flags != id)
|
||||
continue;
|
||||
|
||||
bk_devs[i].num_resources = 1;
|
||||
@ -538,7 +539,6 @@ static void __devinit device_bk_init(struct pm860x_chip *chip,
|
||||
}
|
||||
|
||||
static void __devinit device_led_init(struct pm860x_chip *chip,
|
||||
struct i2c_client *i2c,
|
||||
struct pm860x_platform_data *pdata)
|
||||
{
|
||||
int ret;
|
||||
@ -551,13 +551,12 @@ static void __devinit device_led_init(struct pm860x_chip *chip,
|
||||
pdata->num_leds = ARRAY_SIZE(led_devs);
|
||||
|
||||
for (i = 0; i < pdata->num_leds; i++) {
|
||||
memcpy(&led_pdata[i], &pdata->led[i],
|
||||
sizeof(struct pm860x_led_pdata));
|
||||
led_devs[i].mfd_data = &led_pdata[i];
|
||||
led_devs[i].platform_data = &pdata->led[i];
|
||||
led_devs[i].pdata_size = sizeof(struct pm860x_led_pdata);
|
||||
|
||||
for (j = 0; j < ARRAY_SIZE(led_devs); j++) {
|
||||
id = led_resources[j].start;
|
||||
if (led_pdata[i].flags != id)
|
||||
if (pdata->led[i].flags != id)
|
||||
continue;
|
||||
|
||||
led_devs[i].num_resources = 1;
|
||||
@ -575,12 +574,11 @@ static void __devinit device_led_init(struct pm860x_chip *chip,
|
||||
}
|
||||
|
||||
static void __devinit device_regulator_init(struct pm860x_chip *chip,
|
||||
struct i2c_client *i2c,
|
||||
struct pm860x_platform_data *pdata)
|
||||
{
|
||||
struct regulator_init_data *initdata;
|
||||
int ret;
|
||||
int i, j;
|
||||
int i, seq;
|
||||
|
||||
if ((pdata == NULL) || (pdata->regulator == NULL))
|
||||
return;
|
||||
@ -588,41 +586,21 @@ static void __devinit device_regulator_init(struct pm860x_chip *chip,
|
||||
if (pdata->num_regulators > ARRAY_SIZE(regulator_devs))
|
||||
pdata->num_regulators = ARRAY_SIZE(regulator_devs);
|
||||
|
||||
for (i = 0, j = -1; i < pdata->num_regulators; i++) {
|
||||
for (i = 0, seq = -1; i < pdata->num_regulators; i++) {
|
||||
initdata = &pdata->regulator[i];
|
||||
if (strstr(initdata->constraints.name, "BUCK")) {
|
||||
sscanf(initdata->constraints.name, "BUCK%d", &j);
|
||||
/* BUCK1 ~ BUCK3 */
|
||||
if ((j < 1) || (j > 3)) {
|
||||
dev_err(chip->dev, "Failed to add constraint "
|
||||
"(%s)\n", initdata->constraints.name);
|
||||
goto out;
|
||||
}
|
||||
j = (j - 1) + PM8607_ID_BUCK1;
|
||||
}
|
||||
if (strstr(initdata->constraints.name, "LDO")) {
|
||||
sscanf(initdata->constraints.name, "LDO%d", &j);
|
||||
/* LDO1 ~ LDO15 */
|
||||
if ((j < 1) || (j > 15)) {
|
||||
dev_err(chip->dev, "Failed to add constraint "
|
||||
"(%s)\n", initdata->constraints.name);
|
||||
goto out;
|
||||
}
|
||||
j = (j - 1) + PM8607_ID_LDO1;
|
||||
}
|
||||
if (j == -1) {
|
||||
dev_err(chip->dev, "Failed to add constraint (%s)\n",
|
||||
initdata->constraints.name);
|
||||
seq = *(unsigned int *)initdata->driver_data;
|
||||
if ((seq < 0) || (seq > PM8607_ID_RG_MAX)) {
|
||||
dev_err(chip->dev, "Wrong ID(%d) on regulator(%s)\n",
|
||||
seq, initdata->constraints.name);
|
||||
goto out;
|
||||
}
|
||||
memcpy(®ulator_pdata[i], &pdata->regulator[i],
|
||||
sizeof(struct regulator_init_data));
|
||||
regulator_devs[i].mfd_data = ®ulator_pdata[i];
|
||||
regulator_devs[i].platform_data = &pdata->regulator[i];
|
||||
regulator_devs[i].pdata_size = sizeof(struct regulator_init_data);
|
||||
regulator_devs[i].num_resources = 1;
|
||||
regulator_devs[i].resources = ®ulator_resources[j];
|
||||
regulator_devs[i].resources = ®ulator_resources[seq];
|
||||
|
||||
ret = mfd_add_devices(chip->dev, 0, ®ulator_devs[i], 1,
|
||||
®ulator_resources[j], 0);
|
||||
®ulator_resources[seq], 0);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev, "Failed to add regulator subdev\n");
|
||||
goto out;
|
||||
@ -632,17 +610,35 @@ out:
|
||||
return;
|
||||
}
|
||||
|
||||
static void __devinit device_rtc_init(struct pm860x_chip *chip,
|
||||
struct pm860x_platform_data *pdata)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if ((pdata == NULL))
|
||||
return;
|
||||
|
||||
rtc_devs[0].platform_data = pdata->rtc;
|
||||
rtc_devs[0].pdata_size = sizeof(struct pm860x_rtc_pdata);
|
||||
rtc_devs[0].num_resources = ARRAY_SIZE(rtc_resources);
|
||||
rtc_devs[0].resources = &rtc_resources[0];
|
||||
ret = mfd_add_devices(chip->dev, 0, &rtc_devs[0],
|
||||
ARRAY_SIZE(rtc_devs), &rtc_resources[0],
|
||||
chip->irq_base);
|
||||
if (ret < 0)
|
||||
dev_err(chip->dev, "Failed to add rtc subdev\n");
|
||||
}
|
||||
|
||||
static void __devinit device_touch_init(struct pm860x_chip *chip,
|
||||
struct i2c_client *i2c,
|
||||
struct pm860x_platform_data *pdata)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if ((pdata == NULL) || (pdata->touch == NULL))
|
||||
if (pdata == NULL)
|
||||
return;
|
||||
|
||||
memcpy(&touch_pdata, pdata->touch, sizeof(struct pm860x_touch_pdata));
|
||||
touch_devs[0].mfd_data = &touch_pdata;
|
||||
touch_devs[0].platform_data = pdata->touch;
|
||||
touch_devs[0].pdata_size = sizeof(struct pm860x_touch_pdata);
|
||||
touch_devs[0].num_resources = ARRAY_SIZE(touch_resources);
|
||||
touch_devs[0].resources = &touch_resources[0];
|
||||
ret = mfd_add_devices(chip->dev, 0, &touch_devs[0],
|
||||
@ -653,16 +649,15 @@ static void __devinit device_touch_init(struct pm860x_chip *chip,
|
||||
}
|
||||
|
||||
static void __devinit device_power_init(struct pm860x_chip *chip,
|
||||
struct i2c_client *i2c,
|
||||
struct pm860x_platform_data *pdata)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if ((pdata == NULL) || (pdata->power == NULL))
|
||||
if (pdata == NULL)
|
||||
return;
|
||||
|
||||
memcpy(&power_pdata, pdata->power, sizeof(struct pm860x_power_pdata));
|
||||
power_devs[0].mfd_data = &power_pdata;
|
||||
power_devs[0].platform_data = pdata->power;
|
||||
power_devs[0].pdata_size = sizeof(struct pm860x_power_pdata);
|
||||
power_devs[0].num_resources = ARRAY_SIZE(battery_resources);
|
||||
power_devs[0].resources = &battery_resources[0],
|
||||
ret = mfd_add_devices(chip->dev, 0, &power_devs[0], 1,
|
||||
@ -670,7 +665,8 @@ static void __devinit device_power_init(struct pm860x_chip *chip,
|
||||
if (ret < 0)
|
||||
dev_err(chip->dev, "Failed to add battery subdev\n");
|
||||
|
||||
power_devs[1].mfd_data = &power_pdata;
|
||||
power_devs[1].platform_data = pdata->power;
|
||||
power_devs[1].pdata_size = sizeof(struct pm860x_power_pdata);
|
||||
power_devs[1].num_resources = ARRAY_SIZE(charger_resources);
|
||||
power_devs[1].resources = &charger_resources[0],
|
||||
ret = mfd_add_devices(chip->dev, 0, &power_devs[1], 1,
|
||||
@ -680,7 +676,6 @@ static void __devinit device_power_init(struct pm860x_chip *chip,
|
||||
}
|
||||
|
||||
static void __devinit device_onkey_init(struct pm860x_chip *chip,
|
||||
struct i2c_client *i2c,
|
||||
struct pm860x_platform_data *pdata)
|
||||
{
|
||||
int ret;
|
||||
@ -695,7 +690,6 @@ static void __devinit device_onkey_init(struct pm860x_chip *chip,
|
||||
}
|
||||
|
||||
static void __devinit device_codec_init(struct pm860x_chip *chip,
|
||||
struct i2c_client *i2c,
|
||||
struct pm860x_platform_data *pdata)
|
||||
{
|
||||
int ret;
|
||||
@ -763,11 +757,12 @@ static void __devinit device_8607_init(struct pm860x_chip *chip,
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
device_regulator_init(chip, i2c, pdata);
|
||||
device_onkey_init(chip, i2c, pdata);
|
||||
device_touch_init(chip, i2c, pdata);
|
||||
device_power_init(chip, i2c, pdata);
|
||||
device_codec_init(chip, i2c, pdata);
|
||||
device_regulator_init(chip, pdata);
|
||||
device_rtc_init(chip, pdata);
|
||||
device_onkey_init(chip, pdata);
|
||||
device_touch_init(chip, pdata);
|
||||
device_power_init(chip, pdata);
|
||||
device_codec_init(chip, pdata);
|
||||
out:
|
||||
return;
|
||||
}
|
||||
@ -779,8 +774,8 @@ int __devinit pm860x_device_init(struct pm860x_chip *chip,
|
||||
|
||||
switch (chip->id) {
|
||||
case CHIP_PM8606:
|
||||
device_bk_init(chip, chip->client, pdata);
|
||||
device_led_init(chip, chip->client, pdata);
|
||||
device_bk_init(chip, pdata);
|
||||
device_led_init(chip, pdata);
|
||||
break;
|
||||
case CHIP_PM8607:
|
||||
device_8607_init(chip, chip->client, pdata);
|
||||
@ -790,8 +785,8 @@ int __devinit pm860x_device_init(struct pm860x_chip *chip,
|
||||
if (chip->companion) {
|
||||
switch (chip->id) {
|
||||
case CHIP_PM8607:
|
||||
device_bk_init(chip, chip->companion, pdata);
|
||||
device_led_init(chip, chip->companion, pdata);
|
||||
device_bk_init(chip, pdata);
|
||||
device_led_init(chip, pdata);
|
||||
break;
|
||||
case CHIP_PM8606:
|
||||
device_8607_init(chip, chip->companion, pdata);
|
||||
|
@ -157,6 +157,20 @@ config TPS6507X
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called tps6507x.
|
||||
|
||||
config MFD_TPS6586X
|
||||
bool "TPS6586x Power Management chips"
|
||||
depends on I2C=y && GPIOLIB && GENERIC_HARDIRQS
|
||||
select MFD_CORE
|
||||
help
|
||||
If you say yes here you get support for the TPS6586X series of
|
||||
Power Management chips.
|
||||
This driver provides common support for accessing the device,
|
||||
additional drivers must be enabled in order to use the
|
||||
functionality of the device.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called tps6586x.
|
||||
|
||||
config MENELAUS
|
||||
bool "Texas Instruments TWL92330/Menelaus PM chip"
|
||||
depends on I2C=y && ARCH_OMAP2
|
||||
@ -455,6 +469,20 @@ config MFD_PCF50633
|
||||
facilities, and registers devices for the various functions
|
||||
so that function-specific drivers can bind to them.
|
||||
|
||||
config PCF50633_ADC
|
||||
tristate "Support for NXP PCF50633 ADC"
|
||||
depends on MFD_PCF50633
|
||||
help
|
||||
Say yes here if you want to include support for ADC in the
|
||||
NXP PCF50633 chip.
|
||||
|
||||
config PCF50633_GPIO
|
||||
tristate "Support for NXP PCF50633 GPIO"
|
||||
depends on MFD_PCF50633
|
||||
help
|
||||
Say yes here if you want to include support GPIO for pins on
|
||||
the PCF50633 chip.
|
||||
|
||||
config MFD_MC13783
|
||||
tristate
|
||||
|
||||
@ -470,20 +498,6 @@ config MFD_MC13XXX
|
||||
additional drivers must be enabled in order to use the
|
||||
functionality of the device.
|
||||
|
||||
config PCF50633_ADC
|
||||
tristate "Support for NXP PCF50633 ADC"
|
||||
depends on MFD_PCF50633
|
||||
help
|
||||
Say yes here if you want to include support for ADC in the
|
||||
NXP PCF50633 chip.
|
||||
|
||||
config PCF50633_GPIO
|
||||
tristate "Support for NXP PCF50633 GPIO"
|
||||
depends on MFD_PCF50633
|
||||
help
|
||||
Say yes here if you want to include support GPIO for pins on
|
||||
the PCF50633 chip.
|
||||
|
||||
config ABX500_CORE
|
||||
bool "ST-Ericsson ABX500 Mixed Signal Circuit register functions"
|
||||
default y if ARCH_U300 || ARCH_U8500
|
||||
@ -649,20 +663,6 @@ config MFD_JZ4740_ADC
|
||||
Say yes here if you want support for the ADC unit in the JZ4740 SoC.
|
||||
This driver is necessary for jz4740-battery and jz4740-hwmon driver.
|
||||
|
||||
config MFD_TPS6586X
|
||||
bool "TPS6586x Power Management chips"
|
||||
depends on I2C=y && GPIOLIB && GENERIC_HARDIRQS
|
||||
select MFD_CORE
|
||||
help
|
||||
If you say yes here you get support for the TPS6586X series of
|
||||
Power Management chips.
|
||||
This driver provides common support for accessing the device,
|
||||
additional drivers must be enabled in order to use the
|
||||
functionality of the device.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called tps6586x.
|
||||
|
||||
config MFD_VX855
|
||||
tristate "Support for VIA VX855/VX875 integrated south bridge"
|
||||
depends on PCI
|
||||
@ -691,6 +691,34 @@ config MFD_OMAP_USB_HOST
|
||||
This MFD driver does the required setup functionalities for
|
||||
OMAP USB Host drivers.
|
||||
|
||||
config MFD_PM8XXX
|
||||
tristate
|
||||
|
||||
config MFD_PM8921_CORE
|
||||
tristate "Qualcomm PM8921 PMIC chip"
|
||||
depends on MSM_SSBI
|
||||
select MFD_CORE
|
||||
select MFD_PM8XXX
|
||||
help
|
||||
If you say yes to this option, support will be included for the
|
||||
built-in PM8921 PMIC chip.
|
||||
|
||||
This is required if your board has a PM8921 and uses its features,
|
||||
such as: MPPs, GPIOs, regulators, interrupts, and PWM.
|
||||
|
||||
Say M here if you want to include support for PM8921 chip as a module.
|
||||
This will build a module called "pm8921-core".
|
||||
|
||||
config MFD_PM8XXX_IRQ
|
||||
bool "Support for Qualcomm PM8xxx IRQ features"
|
||||
depends on MFD_PM8XXX
|
||||
default y if MFD_PM8XXX
|
||||
help
|
||||
This is the IRQ driver for Qualcomm PM 8xxx PMIC chips.
|
||||
|
||||
This is required to use certain other PM 8xxx features, such as GPIO
|
||||
and MPP.
|
||||
|
||||
endif # MFD_SUPPORT
|
||||
|
||||
menu "Multimedia Capabilities Port drivers"
|
||||
|
@ -91,3 +91,5 @@ obj-$(CONFIG_MFD_VX855) += vx855.o
|
||||
obj-$(CONFIG_MFD_WL1273_CORE) += wl1273-core.o
|
||||
obj-$(CONFIG_MFD_CS5535) += cs5535-mfd.o
|
||||
obj-$(CONFIG_MFD_OMAP_USB_HOST) += omap-usb-host.o
|
||||
obj-$(CONFIG_MFD_PM8921_CORE) += pm8921-core.o
|
||||
obj-$(CONFIG_MFD_PM8XXX_IRQ) += pm8xxx-irq.o
|
||||
|
@ -949,8 +949,10 @@ static int __devinit ab3100_probe(struct i2c_client *client,
|
||||
goto exit_no_ops;
|
||||
|
||||
/* Set up and register the platform devices. */
|
||||
for (i = 0; i < ARRAY_SIZE(ab3100_devs); i++)
|
||||
ab3100_devs[i].mfd_data = ab3100_plf_data;
|
||||
for (i = 0; i < ARRAY_SIZE(ab3100_devs); i++) {
|
||||
ab3100_devs[i].platform_data = ab3100_plf_data;
|
||||
ab3100_devs[i].pdata_size = sizeof(struct ab3100_platform_data);
|
||||
}
|
||||
|
||||
err = mfd_add_devices(&client->dev, 0, ab3100_devs,
|
||||
ARRAY_SIZE(ab3100_devs), NULL, 0);
|
||||
|
@ -1320,8 +1320,10 @@ static int __init ab3550_probe(struct i2c_client *client,
|
||||
goto exit_no_ops;
|
||||
|
||||
/* Set up and register the platform devices. */
|
||||
for (i = 0; i < AB3550_NUM_DEVICES; i++)
|
||||
ab3550_devs[i].mfd_data = ab3550_plf_data->dev_data[i];
|
||||
for (i = 0; i < AB3550_NUM_DEVICES; i++) {
|
||||
ab3550_devs[i].platform_data = ab3550_plf_data->dev_data[i];
|
||||
ab3550_devs[i].pdata_size = ab3550_plf_data->dev_data_sz[i];
|
||||
}
|
||||
|
||||
err = mfd_add_devices(&client->dev, 0, ab3550_devs,
|
||||
ARRAY_SIZE(ab3550_devs), NULL,
|
||||
|
@ -254,8 +254,9 @@ static void ab8500_irq_sync_unlock(struct irq_data *data)
|
||||
if (new == old)
|
||||
continue;
|
||||
|
||||
/* Interrupt register 12 does'nt exist prior to version 0x20 */
|
||||
if (ab8500_irq_regoffset[i] == 11 && ab8500->chip_id < 0x20)
|
||||
/* Interrupt register 12 doesn't exist prior to version 2.0 */
|
||||
if (ab8500_irq_regoffset[i] == 11 &&
|
||||
ab8500->chip_id < AB8500_CUT2P0)
|
||||
continue;
|
||||
|
||||
ab8500->oldmask[i] = new;
|
||||
@ -307,8 +308,8 @@ static irqreturn_t ab8500_irq(int irq, void *dev)
|
||||
int status;
|
||||
u8 value;
|
||||
|
||||
/* Interrupt register 12 does'nt exist prior to version 0x20 */
|
||||
if (regoffset == 11 && ab8500->chip_id < 0x20)
|
||||
/* Interrupt register 12 doesn't exist prior to version 2.0 */
|
||||
if (regoffset == 11 && ab8500->chip_id < AB8500_CUT2P0)
|
||||
continue;
|
||||
|
||||
status = get_register_interruptible(ab8500, AB8500_INTERRUPT,
|
||||
@ -724,17 +725,15 @@ int __devinit ab8500_init(struct ab8500 *ab8500)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* 0x0 - Early Drop
|
||||
* 0x10 - Cut 1.0
|
||||
* 0x11 - Cut 1.1
|
||||
* 0x20 - Cut 2.0
|
||||
* 0x30 - Cut 3.0
|
||||
*/
|
||||
if (value == 0x0 || value == 0x10 || value == 0x11 || value == 0x20 ||
|
||||
value == 0x30) {
|
||||
switch (value) {
|
||||
case AB8500_CUTEARLY:
|
||||
case AB8500_CUT1P0:
|
||||
case AB8500_CUT1P1:
|
||||
case AB8500_CUT2P0:
|
||||
case AB8500_CUT3P0:
|
||||
dev_info(ab8500->dev, "detected chip, revision: %#x\n", value);
|
||||
} else {
|
||||
break;
|
||||
default:
|
||||
dev_err(ab8500->dev, "unknown chip, revision: %#x\n", value);
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -763,8 +762,9 @@ int __devinit ab8500_init(struct ab8500 *ab8500)
|
||||
|
||||
/* Clear and mask all interrupts */
|
||||
for (i = 0; i < AB8500_NUM_IRQ_REGS; i++) {
|
||||
/* Interrupt register 12 does'nt exist prior to version 0x20 */
|
||||
if (ab8500_irq_regoffset[i] == 11 && ab8500->chip_id < 0x20)
|
||||
/* Interrupt register 12 doesn't exist prior to version 2.0 */
|
||||
if (ab8500_irq_regoffset[i] == 11 &&
|
||||
ab8500->chip_id < AB8500_CUT2P0)
|
||||
continue;
|
||||
|
||||
get_register_interruptible(ab8500, AB8500_INTERRUPT,
|
||||
|
@ -57,6 +57,7 @@
|
||||
#define SW_AVG_16 0x60
|
||||
#define ADC_SW_CONV 0x04
|
||||
#define EN_ICHAR 0x80
|
||||
#define BTEMP_PULL_UP 0x08
|
||||
#define EN_BUF 0x40
|
||||
#define DIS_ZERO 0x00
|
||||
#define GPADC_BUSY 0x01
|
||||
@ -101,6 +102,7 @@ struct adc_cal_data {
|
||||
|
||||
/**
|
||||
* struct ab8500_gpadc - AB8500 GPADC device information
|
||||
* @chip_id ABB chip id
|
||||
* @dev: pointer to the struct device
|
||||
* @node: a list of AB8500 GPADCs, hence prepared for
|
||||
reentrance
|
||||
@ -112,6 +114,7 @@ struct adc_cal_data {
|
||||
* @cal_data array of ADC calibration data structs
|
||||
*/
|
||||
struct ab8500_gpadc {
|
||||
u8 chip_id;
|
||||
struct device *dev;
|
||||
struct list_head node;
|
||||
struct completion ab8500_gpadc_complete;
|
||||
@ -274,6 +277,7 @@ int ab8500_gpadc_convert(struct ab8500_gpadc *gpadc, u8 input)
|
||||
dev_err(gpadc->dev, "gpadc_conversion: enable gpadc failed\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Select the input source and set average samples to 16 */
|
||||
ret = abx500_set_register_interruptible(gpadc->dev, AB8500_GPADC,
|
||||
AB8500_GPADC_CTRL2_REG, (input | SW_AVG_16));
|
||||
@ -282,9 +286,11 @@ int ab8500_gpadc_convert(struct ab8500_gpadc *gpadc, u8 input)
|
||||
"gpadc_conversion: set avg samples failed\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable ADC, buffering, select rising edge and enable ADC path
|
||||
* charging current sense if it needed
|
||||
* charging current sense if it needed, ABB 3.0 needs some special
|
||||
* treatment too.
|
||||
*/
|
||||
switch (input) {
|
||||
case MAIN_CHARGER_C:
|
||||
@ -294,6 +300,23 @@ int ab8500_gpadc_convert(struct ab8500_gpadc *gpadc, u8 input)
|
||||
EN_BUF | EN_ICHAR,
|
||||
EN_BUF | EN_ICHAR);
|
||||
break;
|
||||
case BTEMP_BALL:
|
||||
if (gpadc->chip_id >= AB8500_CUT3P0) {
|
||||
/* Turn on btemp pull-up on ABB 3.0 */
|
||||
ret = abx500_mask_and_set_register_interruptible(
|
||||
gpadc->dev,
|
||||
AB8500_GPADC, AB8500_GPADC_CTRL1_REG,
|
||||
EN_BUF | BTEMP_PULL_UP,
|
||||
EN_BUF | BTEMP_PULL_UP);
|
||||
|
||||
/*
|
||||
* Delay might be needed for ABB8500 cut 3.0, if not, remove
|
||||
* when hardware will be availible
|
||||
*/
|
||||
msleep(1);
|
||||
break;
|
||||
}
|
||||
/* Intentional fallthrough */
|
||||
default:
|
||||
ret = abx500_mask_and_set_register_interruptible(gpadc->dev,
|
||||
AB8500_GPADC, AB8500_GPADC_CTRL1_REG, EN_BUF, EN_BUF);
|
||||
@ -304,6 +327,7 @@ int ab8500_gpadc_convert(struct ab8500_gpadc *gpadc, u8 input)
|
||||
"gpadc_conversion: select falling edge failed\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = abx500_mask_and_set_register_interruptible(gpadc->dev,
|
||||
AB8500_GPADC, AB8500_GPADC_CTRL1_REG, ADC_SW_CONV, ADC_SW_CONV);
|
||||
if (ret < 0) {
|
||||
@ -552,6 +576,14 @@ static int __devinit ab8500_gpadc_probe(struct platform_device *pdev)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Get Chip ID of the ABB ASIC */
|
||||
ret = abx500_get_chip_id(gpadc->dev);
|
||||
if (ret < 0) {
|
||||
dev_err(gpadc->dev, "failed to get chip ID\n");
|
||||
goto fail_irq;
|
||||
}
|
||||
gpadc->chip_id = (u8) ret;
|
||||
|
||||
/* VTVout LDO used to power up ab8500-GPADC */
|
||||
gpadc->regu = regulator_get(&pdev->dev, "vddadc");
|
||||
if (IS_ERR(gpadc->regu)) {
|
||||
|
@ -88,19 +88,19 @@ struct asic3 {
|
||||
|
||||
static int asic3_gpio_get(struct gpio_chip *chip, unsigned offset);
|
||||
|
||||
static inline void asic3_write_register(struct asic3 *asic,
|
||||
unsigned int reg, u32 value)
|
||||
void asic3_write_register(struct asic3 *asic, unsigned int reg, u32 value)
|
||||
{
|
||||
iowrite16(value, asic->mapping +
|
||||
(reg >> asic->bus_shift));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(asic3_write_register);
|
||||
|
||||
static inline u32 asic3_read_register(struct asic3 *asic,
|
||||
unsigned int reg)
|
||||
u32 asic3_read_register(struct asic3 *asic, unsigned int reg)
|
||||
{
|
||||
return ioread16(asic->mapping +
|
||||
(reg >> asic->bus_shift));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(asic3_read_register);
|
||||
|
||||
static void asic3_set_register(struct asic3 *asic, u32 reg, u32 bits, bool set)
|
||||
{
|
||||
@ -676,7 +676,8 @@ static struct mfd_cell asic3_cell_ds1wm = {
|
||||
.name = "ds1wm",
|
||||
.enable = ds1wm_enable,
|
||||
.disable = ds1wm_disable,
|
||||
.mfd_data = &ds1wm_pdata,
|
||||
.platform_data = &ds1wm_pdata,
|
||||
.pdata_size = sizeof(ds1wm_pdata),
|
||||
.num_resources = ARRAY_SIZE(ds1wm_resources),
|
||||
.resources = ds1wm_resources,
|
||||
};
|
||||
@ -777,12 +778,61 @@ static struct mfd_cell asic3_cell_mmc = {
|
||||
.name = "tmio-mmc",
|
||||
.enable = asic3_mmc_enable,
|
||||
.disable = asic3_mmc_disable,
|
||||
.mfd_data = &asic3_mmc_data,
|
||||
.platform_data = &asic3_mmc_data,
|
||||
.pdata_size = sizeof(asic3_mmc_data),
|
||||
.num_resources = ARRAY_SIZE(asic3_mmc_resources),
|
||||
.resources = asic3_mmc_resources,
|
||||
};
|
||||
|
||||
static const int clock_ledn[ASIC3_NUM_LEDS] = {
|
||||
[0] = ASIC3_CLOCK_LED0,
|
||||
[1] = ASIC3_CLOCK_LED1,
|
||||
[2] = ASIC3_CLOCK_LED2,
|
||||
};
|
||||
|
||||
static int asic3_leds_enable(struct platform_device *pdev)
|
||||
{
|
||||
const struct mfd_cell *cell = mfd_get_cell(pdev);
|
||||
struct asic3 *asic = dev_get_drvdata(pdev->dev.parent);
|
||||
|
||||
asic3_clk_enable(asic, &asic->clocks[clock_ledn[cell->id]]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int asic3_leds_disable(struct platform_device *pdev)
|
||||
{
|
||||
const struct mfd_cell *cell = mfd_get_cell(pdev);
|
||||
struct asic3 *asic = dev_get_drvdata(pdev->dev.parent);
|
||||
|
||||
asic3_clk_disable(asic, &asic->clocks[clock_ledn[cell->id]]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct mfd_cell asic3_cell_leds[ASIC3_NUM_LEDS] = {
|
||||
[0] = {
|
||||
.name = "leds-asic3",
|
||||
.id = 0,
|
||||
.enable = asic3_leds_enable,
|
||||
.disable = asic3_leds_disable,
|
||||
},
|
||||
[1] = {
|
||||
.name = "leds-asic3",
|
||||
.id = 1,
|
||||
.enable = asic3_leds_enable,
|
||||
.disable = asic3_leds_disable,
|
||||
},
|
||||
[2] = {
|
||||
.name = "leds-asic3",
|
||||
.id = 2,
|
||||
.enable = asic3_leds_enable,
|
||||
.disable = asic3_leds_disable,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init asic3_mfd_probe(struct platform_device *pdev,
|
||||
struct asic3_platform_data *pdata,
|
||||
struct resource *mem)
|
||||
{
|
||||
struct asic3 *asic = platform_get_drvdata(pdev);
|
||||
@ -806,7 +856,8 @@ static int __init asic3_mfd_probe(struct platform_device *pdev,
|
||||
|
||||
/* MMC */
|
||||
asic->tmio_cnf = ioremap((ASIC3_SD_CONFIG_BASE >> asic->bus_shift) +
|
||||
mem_sdio->start, 0x400 >> asic->bus_shift);
|
||||
mem_sdio->start,
|
||||
ASIC3_SD_CONFIG_SIZE >> asic->bus_shift);
|
||||
if (!asic->tmio_cnf) {
|
||||
ret = -ENOMEM;
|
||||
dev_dbg(asic->dev, "Couldn't ioremap SD_CONFIG\n");
|
||||
@ -820,9 +871,23 @@ static int __init asic3_mfd_probe(struct platform_device *pdev,
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
if (mem_sdio && (irq >= 0))
|
||||
if (mem_sdio && (irq >= 0)) {
|
||||
ret = mfd_add_devices(&pdev->dev, pdev->id,
|
||||
&asic3_cell_mmc, 1, mem_sdio, irq);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (pdata->leds) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ASIC3_NUM_LEDS; ++i) {
|
||||
asic3_cell_leds[i].platform_data = &pdata->leds[i];
|
||||
asic3_cell_leds[i].pdata_size = sizeof(pdata->leds[i]);
|
||||
}
|
||||
ret = mfd_add_devices(&pdev->dev, 0,
|
||||
asic3_cell_leds, ASIC3_NUM_LEDS, NULL, 0);
|
||||
}
|
||||
|
||||
out:
|
||||
return ret;
|
||||
@ -903,7 +968,7 @@ static int __init asic3_probe(struct platform_device *pdev)
|
||||
*/
|
||||
memcpy(asic->clocks, asic3_clk_init, sizeof(asic3_clk_init));
|
||||
|
||||
asic3_mfd_probe(pdev, mem);
|
||||
asic3_mfd_probe(pdev, pdata, mem);
|
||||
|
||||
dev_info(asic->dev, "ASIC3 Core driver\n");
|
||||
|
||||
|
@ -119,12 +119,14 @@ static int __init davinci_vc_probe(struct platform_device *pdev)
|
||||
/* Voice codec interface client */
|
||||
cell = &davinci_vc->cells[DAVINCI_VC_VCIF_CELL];
|
||||
cell->name = "davinci-vcif";
|
||||
cell->mfd_data = davinci_vc;
|
||||
cell->platform_data = davinci_vc;
|
||||
cell->pdata_size = sizeof(*davinci_vc);
|
||||
|
||||
/* Voice codec CQ93VC client */
|
||||
cell = &davinci_vc->cells[DAVINCI_VC_CQ93VC_CELL];
|
||||
cell->name = "cq93vc-codec";
|
||||
cell->mfd_data = davinci_vc;
|
||||
cell->platform_data = davinci_vc;
|
||||
cell->pdata_size = sizeof(*davinci_vc);
|
||||
|
||||
ret = mfd_add_devices(&pdev->dev, pdev->id, davinci_vc->cells,
|
||||
DAVINCI_VC_CELLS, NULL, 0);
|
||||
|
@ -117,7 +117,8 @@ static struct mfd_cell ds1wm_cell __initdata = {
|
||||
.name = "ds1wm",
|
||||
.enable = ds1wm_enable,
|
||||
.disable = ds1wm_disable,
|
||||
.mfd_data = &ds1wm_pdata,
|
||||
.platform_data = &ds1wm_pdata,
|
||||
.pdata_size = sizeof(ds1wm_pdata),
|
||||
.num_resources = 2,
|
||||
.resources = ds1wm_resources,
|
||||
};
|
||||
@ -172,6 +173,8 @@ static int __init pasic3_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
if (pdata && pdata->led_pdata) {
|
||||
led_cell.platform_data = pdata->led_pdata;
|
||||
led_cell.pdata_size = sizeof(struct pasic3_leds_machinfo);
|
||||
ret = mfd_add_devices(&pdev->dev, pdev->id, &led_cell, 1, r, 0);
|
||||
if (ret < 0)
|
||||
dev_warn(dev, "failed to register LED device\n");
|
||||
|
@ -86,7 +86,8 @@ static int __devinit cmodio_setup_subdevice(struct cmodio_device *priv,
|
||||
|
||||
/* Add platform data */
|
||||
pdata->modno = modno;
|
||||
cell->mfd_data = pdata;
|
||||
cell->platform_data = pdata;
|
||||
cell->pdata_size = sizeof(*pdata);
|
||||
|
||||
/* MODULbus registers -- PCI BAR3 is big-endian MODULbus access */
|
||||
res->flags = IORESOURCE_MEM;
|
||||
|
@ -627,7 +627,7 @@ int __devinit max8925_device_init(struct max8925_chip *chip,
|
||||
goto out_dev;
|
||||
}
|
||||
|
||||
if (pdata && pdata->regulator[0]) {
|
||||
if (pdata) {
|
||||
ret = mfd_add_devices(chip->dev, 0, ®ulator_devs[0],
|
||||
ARRAY_SIZE(regulator_devs),
|
||||
®ulator_resources[0], 0);
|
||||
|
@ -683,13 +683,14 @@ out:
|
||||
EXPORT_SYMBOL_GPL(mc13783_adc_do_conversion);
|
||||
|
||||
static int mc13xxx_add_subdevice_pdata(struct mc13xxx *mc13xxx,
|
||||
const char *format, void *pdata)
|
||||
const char *format, void *pdata, size_t pdata_size)
|
||||
{
|
||||
char buf[30];
|
||||
const char *name = mc13xxx_get_chipname(mc13xxx);
|
||||
|
||||
struct mfd_cell cell = {
|
||||
.mfd_data = pdata,
|
||||
.platform_data = pdata,
|
||||
.pdata_size = pdata_size,
|
||||
};
|
||||
|
||||
/* there is no asnprintf in the kernel :-( */
|
||||
@ -705,7 +706,7 @@ static int mc13xxx_add_subdevice_pdata(struct mc13xxx *mc13xxx,
|
||||
|
||||
static int mc13xxx_add_subdevice(struct mc13xxx *mc13xxx, const char *format)
|
||||
{
|
||||
return mc13xxx_add_subdevice_pdata(mc13xxx, format, NULL);
|
||||
return mc13xxx_add_subdevice_pdata(mc13xxx, format, NULL, 0);
|
||||
}
|
||||
|
||||
static int mc13xxx_probe(struct spi_device *spi)
|
||||
@ -764,7 +765,7 @@ err_revision:
|
||||
|
||||
if (pdata->flags & MC13XXX_USE_REGULATOR) {
|
||||
mc13xxx_add_subdevice_pdata(mc13xxx, "%s-regulator",
|
||||
&pdata->regulators);
|
||||
&pdata->regulators, sizeof(pdata->regulators));
|
||||
}
|
||||
|
||||
if (pdata->flags & MC13XXX_USE_RTC)
|
||||
@ -774,7 +775,8 @@ err_revision:
|
||||
mc13xxx_add_subdevice(mc13xxx, "%s-ts");
|
||||
|
||||
if (pdata->flags & MC13XXX_USE_LED)
|
||||
mc13xxx_add_subdevice_pdata(mc13xxx, "%s-led", pdata->leds);
|
||||
mc13xxx_add_subdevice_pdata(mc13xxx, "%s-led",
|
||||
pdata->leds, sizeof(*pdata->leds));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -88,6 +88,13 @@ static int mfd_add_device(struct device *parent, int id,
|
||||
|
||||
pdev->dev.parent = parent;
|
||||
|
||||
if (cell->pdata_size) {
|
||||
ret = platform_device_add_data(pdev,
|
||||
cell->platform_data, cell->pdata_size);
|
||||
if (ret)
|
||||
goto fail_res;
|
||||
}
|
||||
|
||||
ret = mfd_platform_add_cell(pdev, cell);
|
||||
if (ret)
|
||||
goto fail_res;
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <plat/usb.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#define USBHS_DRIVER_NAME "usbhs-omap"
|
||||
#define OMAP_EHCI_DEVICE "ehci-omap"
|
||||
@ -146,9 +147,6 @@
|
||||
|
||||
|
||||
struct usbhs_hcd_omap {
|
||||
struct clk *usbhost_ick;
|
||||
struct clk *usbhost_hs_fck;
|
||||
struct clk *usbhost_fs_fck;
|
||||
struct clk *xclk60mhsp1_ck;
|
||||
struct clk *xclk60mhsp2_ck;
|
||||
struct clk *utmi_p1_fck;
|
||||
@ -158,8 +156,6 @@ struct usbhs_hcd_omap {
|
||||
struct clk *usbhost_p2_fck;
|
||||
struct clk *usbtll_p2_fck;
|
||||
struct clk *init_60m_fclk;
|
||||
struct clk *usbtll_fck;
|
||||
struct clk *usbtll_ick;
|
||||
|
||||
void __iomem *uhh_base;
|
||||
void __iomem *tll_base;
|
||||
@ -281,6 +277,7 @@ static int omap_usbhs_alloc_children(struct platform_device *pdev)
|
||||
|
||||
if (!ehci) {
|
||||
dev_err(dev, "omap_usbhs_alloc_child failed\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_end;
|
||||
}
|
||||
|
||||
@ -304,13 +301,14 @@ static int omap_usbhs_alloc_children(struct platform_device *pdev)
|
||||
sizeof(*ohci_data), dev);
|
||||
if (!ohci) {
|
||||
dev_err(dev, "omap_usbhs_alloc_child failed\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_ehci;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_ehci:
|
||||
platform_device_put(ehci);
|
||||
platform_device_unregister(ehci);
|
||||
|
||||
err_end:
|
||||
return ret;
|
||||
@ -351,46 +349,13 @@ static int __devinit usbhs_omap_probe(struct platform_device *pdev)
|
||||
omap->platdata.ehci_data = pdata->ehci_data;
|
||||
omap->platdata.ohci_data = pdata->ohci_data;
|
||||
|
||||
omap->usbhost_ick = clk_get(dev, "usbhost_ick");
|
||||
if (IS_ERR(omap->usbhost_ick)) {
|
||||
ret = PTR_ERR(omap->usbhost_ick);
|
||||
dev_err(dev, "usbhost_ick failed error:%d\n", ret);
|
||||
goto err_end;
|
||||
}
|
||||
|
||||
omap->usbhost_hs_fck = clk_get(dev, "hs_fck");
|
||||
if (IS_ERR(omap->usbhost_hs_fck)) {
|
||||
ret = PTR_ERR(omap->usbhost_hs_fck);
|
||||
dev_err(dev, "usbhost_hs_fck failed error:%d\n", ret);
|
||||
goto err_usbhost_ick;
|
||||
}
|
||||
|
||||
omap->usbhost_fs_fck = clk_get(dev, "fs_fck");
|
||||
if (IS_ERR(omap->usbhost_fs_fck)) {
|
||||
ret = PTR_ERR(omap->usbhost_fs_fck);
|
||||
dev_err(dev, "usbhost_fs_fck failed error:%d\n", ret);
|
||||
goto err_usbhost_hs_fck;
|
||||
}
|
||||
|
||||
omap->usbtll_fck = clk_get(dev, "usbtll_fck");
|
||||
if (IS_ERR(omap->usbtll_fck)) {
|
||||
ret = PTR_ERR(omap->usbtll_fck);
|
||||
dev_err(dev, "usbtll_fck failed error:%d\n", ret);
|
||||
goto err_usbhost_fs_fck;
|
||||
}
|
||||
|
||||
omap->usbtll_ick = clk_get(dev, "usbtll_ick");
|
||||
if (IS_ERR(omap->usbtll_ick)) {
|
||||
ret = PTR_ERR(omap->usbtll_ick);
|
||||
dev_err(dev, "usbtll_ick failed error:%d\n", ret);
|
||||
goto err_usbtll_fck;
|
||||
}
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
omap->utmi_p1_fck = clk_get(dev, "utmi_p1_gfclk");
|
||||
if (IS_ERR(omap->utmi_p1_fck)) {
|
||||
ret = PTR_ERR(omap->utmi_p1_fck);
|
||||
dev_err(dev, "utmi_p1_gfclk failed error:%d\n", ret);
|
||||
goto err_usbtll_ick;
|
||||
goto err_end;
|
||||
}
|
||||
|
||||
omap->xclk60mhsp1_ck = clk_get(dev, "xclk60mhsp1_ck");
|
||||
@ -520,22 +485,8 @@ err_xclk60mhsp1_ck:
|
||||
err_utmi_p1_fck:
|
||||
clk_put(omap->utmi_p1_fck);
|
||||
|
||||
err_usbtll_ick:
|
||||
clk_put(omap->usbtll_ick);
|
||||
|
||||
err_usbtll_fck:
|
||||
clk_put(omap->usbtll_fck);
|
||||
|
||||
err_usbhost_fs_fck:
|
||||
clk_put(omap->usbhost_fs_fck);
|
||||
|
||||
err_usbhost_hs_fck:
|
||||
clk_put(omap->usbhost_hs_fck);
|
||||
|
||||
err_usbhost_ick:
|
||||
clk_put(omap->usbhost_ick);
|
||||
|
||||
err_end:
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
kfree(omap);
|
||||
|
||||
end_probe:
|
||||
@ -569,11 +520,7 @@ static int __devexit usbhs_omap_remove(struct platform_device *pdev)
|
||||
clk_put(omap->utmi_p2_fck);
|
||||
clk_put(omap->xclk60mhsp1_ck);
|
||||
clk_put(omap->utmi_p1_fck);
|
||||
clk_put(omap->usbtll_ick);
|
||||
clk_put(omap->usbtll_fck);
|
||||
clk_put(omap->usbhost_fs_fck);
|
||||
clk_put(omap->usbhost_hs_fck);
|
||||
clk_put(omap->usbhost_ick);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
kfree(omap);
|
||||
|
||||
return 0;
|
||||
@ -693,7 +640,6 @@ static int usbhs_enable(struct device *dev)
|
||||
struct usbhs_omap_platform_data *pdata = &omap->platdata;
|
||||
unsigned long flags = 0;
|
||||
int ret = 0;
|
||||
unsigned long timeout;
|
||||
unsigned reg;
|
||||
|
||||
dev_dbg(dev, "starting TI HSUSB Controller\n");
|
||||
@ -706,11 +652,7 @@ static int usbhs_enable(struct device *dev)
|
||||
if (omap->count > 0)
|
||||
goto end_count;
|
||||
|
||||
clk_enable(omap->usbhost_ick);
|
||||
clk_enable(omap->usbhost_hs_fck);
|
||||
clk_enable(omap->usbhost_fs_fck);
|
||||
clk_enable(omap->usbtll_fck);
|
||||
clk_enable(omap->usbtll_ick);
|
||||
pm_runtime_get_sync(dev);
|
||||
|
||||
if (pdata->ehci_data->phy_reset) {
|
||||
if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) {
|
||||
@ -734,50 +676,6 @@ static int usbhs_enable(struct device *dev)
|
||||
omap->usbhs_rev = usbhs_read(omap->uhh_base, OMAP_UHH_REVISION);
|
||||
dev_dbg(dev, "OMAP UHH_REVISION 0x%x\n", omap->usbhs_rev);
|
||||
|
||||
/* perform TLL soft reset, and wait until reset is complete */
|
||||
usbhs_write(omap->tll_base, OMAP_USBTLL_SYSCONFIG,
|
||||
OMAP_USBTLL_SYSCONFIG_SOFTRESET);
|
||||
|
||||
/* Wait for TLL reset to complete */
|
||||
timeout = jiffies + msecs_to_jiffies(1000);
|
||||
while (!(usbhs_read(omap->tll_base, OMAP_USBTLL_SYSSTATUS)
|
||||
& OMAP_USBTLL_SYSSTATUS_RESETDONE)) {
|
||||
cpu_relax();
|
||||
|
||||
if (time_after(jiffies, timeout)) {
|
||||
dev_dbg(dev, "operation timed out\n");
|
||||
ret = -EINVAL;
|
||||
goto err_tll;
|
||||
}
|
||||
}
|
||||
|
||||
dev_dbg(dev, "TLL RESET DONE\n");
|
||||
|
||||
/* (1<<3) = no idle mode only for initial debugging */
|
||||
usbhs_write(omap->tll_base, OMAP_USBTLL_SYSCONFIG,
|
||||
OMAP_USBTLL_SYSCONFIG_ENAWAKEUP |
|
||||
OMAP_USBTLL_SYSCONFIG_SIDLEMODE |
|
||||
OMAP_USBTLL_SYSCONFIG_AUTOIDLE);
|
||||
|
||||
/* Put UHH in NoIdle/NoStandby mode */
|
||||
reg = usbhs_read(omap->uhh_base, OMAP_UHH_SYSCONFIG);
|
||||
if (is_omap_usbhs_rev1(omap)) {
|
||||
reg |= (OMAP_UHH_SYSCONFIG_ENAWAKEUP
|
||||
| OMAP_UHH_SYSCONFIG_SIDLEMODE
|
||||
| OMAP_UHH_SYSCONFIG_CACTIVITY
|
||||
| OMAP_UHH_SYSCONFIG_MIDLEMODE);
|
||||
reg &= ~OMAP_UHH_SYSCONFIG_AUTOIDLE;
|
||||
|
||||
|
||||
} else if (is_omap_usbhs_rev2(omap)) {
|
||||
reg &= ~OMAP4_UHH_SYSCONFIG_IDLEMODE_CLEAR;
|
||||
reg |= OMAP4_UHH_SYSCONFIG_NOIDLE;
|
||||
reg &= ~OMAP4_UHH_SYSCONFIG_STDBYMODE_CLEAR;
|
||||
reg |= OMAP4_UHH_SYSCONFIG_NOSTDBY;
|
||||
}
|
||||
|
||||
usbhs_write(omap->uhh_base, OMAP_UHH_SYSCONFIG, reg);
|
||||
|
||||
reg = usbhs_read(omap->uhh_base, OMAP_UHH_HOSTCONFIG);
|
||||
/* setup ULPI bypass and burst configurations */
|
||||
reg |= (OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN
|
||||
@ -917,6 +815,8 @@ end_count:
|
||||
return 0;
|
||||
|
||||
err_tll:
|
||||
pm_runtime_put_sync(dev);
|
||||
spin_unlock_irqrestore(&omap->lock, flags);
|
||||
if (pdata->ehci_data->phy_reset) {
|
||||
if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0]))
|
||||
gpio_free(pdata->ehci_data->reset_gpio_port[0]);
|
||||
@ -924,13 +824,6 @@ err_tll:
|
||||
if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1]))
|
||||
gpio_free(pdata->ehci_data->reset_gpio_port[1]);
|
||||
}
|
||||
|
||||
clk_disable(omap->usbtll_ick);
|
||||
clk_disable(omap->usbtll_fck);
|
||||
clk_disable(omap->usbhost_fs_fck);
|
||||
clk_disable(omap->usbhost_hs_fck);
|
||||
clk_disable(omap->usbhost_ick);
|
||||
spin_unlock_irqrestore(&omap->lock, flags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -994,6 +887,20 @@ static void usbhs_disable(struct device *dev)
|
||||
dev_dbg(dev, "operation timed out\n");
|
||||
}
|
||||
|
||||
if (is_omap_usbhs_rev2(omap)) {
|
||||
if (is_ehci_tll_mode(pdata->port_mode[0]))
|
||||
clk_enable(omap->usbtll_p1_fck);
|
||||
if (is_ehci_tll_mode(pdata->port_mode[1]))
|
||||
clk_enable(omap->usbtll_p2_fck);
|
||||
clk_disable(omap->utmi_p2_fck);
|
||||
clk_disable(omap->utmi_p1_fck);
|
||||
}
|
||||
|
||||
pm_runtime_put_sync(dev);
|
||||
|
||||
/* The gpio_free migh sleep; so unlock the spinlock */
|
||||
spin_unlock_irqrestore(&omap->lock, flags);
|
||||
|
||||
if (pdata->ehci_data->phy_reset) {
|
||||
if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0]))
|
||||
gpio_free(pdata->ehci_data->reset_gpio_port[0]);
|
||||
@ -1001,14 +908,7 @@ static void usbhs_disable(struct device *dev)
|
||||
if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1]))
|
||||
gpio_free(pdata->ehci_data->reset_gpio_port[1]);
|
||||
}
|
||||
|
||||
clk_disable(omap->utmi_p2_fck);
|
||||
clk_disable(omap->utmi_p1_fck);
|
||||
clk_disable(omap->usbtll_ick);
|
||||
clk_disable(omap->usbtll_fck);
|
||||
clk_disable(omap->usbhost_fs_fck);
|
||||
clk_disable(omap->usbhost_hs_fck);
|
||||
clk_disable(omap->usbhost_ick);
|
||||
return;
|
||||
|
||||
end_disble:
|
||||
spin_unlock_irqrestore(&omap->lock, flags);
|
||||
|
212
drivers/mfd/pm8921-core.c
Normal file
212
drivers/mfd/pm8921-core.c
Normal file
@ -0,0 +1,212 @@
|
||||
/*
|
||||
* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "%s: " fmt, __func__
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/msm_ssbi.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/pm8xxx/pm8921.h>
|
||||
#include <linux/mfd/pm8xxx/core.h>
|
||||
|
||||
#define REG_HWREV 0x002 /* PMIC4 revision */
|
||||
#define REG_HWREV_2 0x0E8 /* PMIC4 revision 2 */
|
||||
|
||||
struct pm8921 {
|
||||
struct device *dev;
|
||||
struct pm_irq_chip *irq_chip;
|
||||
};
|
||||
|
||||
static int pm8921_readb(const struct device *dev, u16 addr, u8 *val)
|
||||
{
|
||||
const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev);
|
||||
const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data;
|
||||
|
||||
return msm_ssbi_read(pmic->dev->parent, addr, val, 1);
|
||||
}
|
||||
|
||||
static int pm8921_writeb(const struct device *dev, u16 addr, u8 val)
|
||||
{
|
||||
const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev);
|
||||
const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data;
|
||||
|
||||
return msm_ssbi_write(pmic->dev->parent, addr, &val, 1);
|
||||
}
|
||||
|
||||
static int pm8921_read_buf(const struct device *dev, u16 addr, u8 *buf,
|
||||
int cnt)
|
||||
{
|
||||
const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev);
|
||||
const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data;
|
||||
|
||||
return msm_ssbi_read(pmic->dev->parent, addr, buf, cnt);
|
||||
}
|
||||
|
||||
static int pm8921_write_buf(const struct device *dev, u16 addr, u8 *buf,
|
||||
int cnt)
|
||||
{
|
||||
const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev);
|
||||
const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data;
|
||||
|
||||
return msm_ssbi_write(pmic->dev->parent, addr, buf, cnt);
|
||||
}
|
||||
|
||||
static int pm8921_read_irq_stat(const struct device *dev, int irq)
|
||||
{
|
||||
const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev);
|
||||
const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data;
|
||||
|
||||
return pm8xxx_get_irq_stat(pmic->irq_chip, irq);
|
||||
}
|
||||
|
||||
static struct pm8xxx_drvdata pm8921_drvdata = {
|
||||
.pmic_readb = pm8921_readb,
|
||||
.pmic_writeb = pm8921_writeb,
|
||||
.pmic_read_buf = pm8921_read_buf,
|
||||
.pmic_write_buf = pm8921_write_buf,
|
||||
.pmic_read_irq_stat = pm8921_read_irq_stat,
|
||||
};
|
||||
|
||||
static int __devinit pm8921_add_subdevices(const struct pm8921_platform_data
|
||||
*pdata,
|
||||
struct pm8921 *pmic,
|
||||
u32 rev)
|
||||
{
|
||||
int ret = 0, irq_base = 0;
|
||||
struct pm_irq_chip *irq_chip;
|
||||
|
||||
if (pdata->irq_pdata) {
|
||||
pdata->irq_pdata->irq_cdata.nirqs = PM8921_NR_IRQS;
|
||||
pdata->irq_pdata->irq_cdata.rev = rev;
|
||||
irq_base = pdata->irq_pdata->irq_base;
|
||||
irq_chip = pm8xxx_irq_init(pmic->dev, pdata->irq_pdata);
|
||||
|
||||
if (IS_ERR(irq_chip)) {
|
||||
pr_err("Failed to init interrupts ret=%ld\n",
|
||||
PTR_ERR(irq_chip));
|
||||
return PTR_ERR(irq_chip);
|
||||
}
|
||||
pmic->irq_chip = irq_chip;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devinit pm8921_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct pm8921_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct pm8921 *pmic;
|
||||
int rc;
|
||||
u8 val;
|
||||
u32 rev;
|
||||
|
||||
if (!pdata) {
|
||||
pr_err("missing platform data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pmic = kzalloc(sizeof(struct pm8921), GFP_KERNEL);
|
||||
if (!pmic) {
|
||||
pr_err("Cannot alloc pm8921 struct\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Read PMIC chip revision */
|
||||
rc = msm_ssbi_read(pdev->dev.parent, REG_HWREV, &val, sizeof(val));
|
||||
if (rc) {
|
||||
pr_err("Failed to read hw rev reg %d:rc=%d\n", REG_HWREV, rc);
|
||||
goto err_read_rev;
|
||||
}
|
||||
pr_info("PMIC revision 1: %02X\n", val);
|
||||
rev = val;
|
||||
|
||||
/* Read PMIC chip revision 2 */
|
||||
rc = msm_ssbi_read(pdev->dev.parent, REG_HWREV_2, &val, sizeof(val));
|
||||
if (rc) {
|
||||
pr_err("Failed to read hw rev 2 reg %d:rc=%d\n",
|
||||
REG_HWREV_2, rc);
|
||||
goto err_read_rev;
|
||||
}
|
||||
pr_info("PMIC revision 2: %02X\n", val);
|
||||
rev |= val << BITS_PER_BYTE;
|
||||
|
||||
pmic->dev = &pdev->dev;
|
||||
pm8921_drvdata.pm_chip_data = pmic;
|
||||
platform_set_drvdata(pdev, &pm8921_drvdata);
|
||||
|
||||
rc = pm8921_add_subdevices(pdata, pmic, rev);
|
||||
if (rc) {
|
||||
pr_err("Cannot add subdevices rc=%d\n", rc);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* gpio might not work if no irq device is found */
|
||||
WARN_ON(pmic->irq_chip == NULL);
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
mfd_remove_devices(pmic->dev);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
err_read_rev:
|
||||
kfree(pmic);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int __devexit pm8921_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct pm8xxx_drvdata *drvdata;
|
||||
struct pm8921 *pmic = NULL;
|
||||
|
||||
drvdata = platform_get_drvdata(pdev);
|
||||
if (drvdata)
|
||||
pmic = drvdata->pm_chip_data;
|
||||
if (pmic)
|
||||
mfd_remove_devices(pmic->dev);
|
||||
if (pmic->irq_chip) {
|
||||
pm8xxx_irq_exit(pmic->irq_chip);
|
||||
pmic->irq_chip = NULL;
|
||||
}
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
kfree(pmic);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver pm8921_driver = {
|
||||
.probe = pm8921_probe,
|
||||
.remove = __devexit_p(pm8921_remove),
|
||||
.driver = {
|
||||
.name = "pm8921-core",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init pm8921_init(void)
|
||||
{
|
||||
return platform_driver_register(&pm8921_driver);
|
||||
}
|
||||
subsys_initcall(pm8921_init);
|
||||
|
||||
static void __exit pm8921_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&pm8921_driver);
|
||||
}
|
||||
module_exit(pm8921_exit);
|
||||
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_DESCRIPTION("PMIC 8921 core driver");
|
||||
MODULE_VERSION("1.0");
|
||||
MODULE_ALIAS("platform:pm8921-core");
|
371
drivers/mfd/pm8xxx-irq.c
Normal file
371
drivers/mfd/pm8xxx-irq.c
Normal file
@ -0,0 +1,371 @@
|
||||
/*
|
||||
* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "%s: " fmt, __func__
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mfd/pm8xxx/core.h>
|
||||
#include <linux/mfd/pm8xxx/irq.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
/* PMIC8xxx IRQ */
|
||||
|
||||
#define SSBI_REG_ADDR_IRQ_BASE 0x1BB
|
||||
|
||||
#define SSBI_REG_ADDR_IRQ_ROOT (SSBI_REG_ADDR_IRQ_BASE + 0)
|
||||
#define SSBI_REG_ADDR_IRQ_M_STATUS1 (SSBI_REG_ADDR_IRQ_BASE + 1)
|
||||
#define SSBI_REG_ADDR_IRQ_M_STATUS2 (SSBI_REG_ADDR_IRQ_BASE + 2)
|
||||
#define SSBI_REG_ADDR_IRQ_M_STATUS3 (SSBI_REG_ADDR_IRQ_BASE + 3)
|
||||
#define SSBI_REG_ADDR_IRQ_M_STATUS4 (SSBI_REG_ADDR_IRQ_BASE + 4)
|
||||
#define SSBI_REG_ADDR_IRQ_BLK_SEL (SSBI_REG_ADDR_IRQ_BASE + 5)
|
||||
#define SSBI_REG_ADDR_IRQ_IT_STATUS (SSBI_REG_ADDR_IRQ_BASE + 6)
|
||||
#define SSBI_REG_ADDR_IRQ_CONFIG (SSBI_REG_ADDR_IRQ_BASE + 7)
|
||||
#define SSBI_REG_ADDR_IRQ_RT_STATUS (SSBI_REG_ADDR_IRQ_BASE + 8)
|
||||
|
||||
#define PM_IRQF_LVL_SEL 0x01 /* level select */
|
||||
#define PM_IRQF_MASK_FE 0x02 /* mask falling edge */
|
||||
#define PM_IRQF_MASK_RE 0x04 /* mask rising edge */
|
||||
#define PM_IRQF_CLR 0x08 /* clear interrupt */
|
||||
#define PM_IRQF_BITS_MASK 0x70
|
||||
#define PM_IRQF_BITS_SHIFT 4
|
||||
#define PM_IRQF_WRITE 0x80
|
||||
|
||||
#define PM_IRQF_MASK_ALL (PM_IRQF_MASK_FE | \
|
||||
PM_IRQF_MASK_RE)
|
||||
|
||||
struct pm_irq_chip {
|
||||
struct device *dev;
|
||||
spinlock_t pm_irq_lock;
|
||||
unsigned int devirq;
|
||||
unsigned int irq_base;
|
||||
unsigned int num_irqs;
|
||||
unsigned int num_blocks;
|
||||
unsigned int num_masters;
|
||||
u8 config[0];
|
||||
};
|
||||
|
||||
static int pm8xxx_read_root_irq(const struct pm_irq_chip *chip, u8 *rp)
|
||||
{
|
||||
return pm8xxx_readb(chip->dev, SSBI_REG_ADDR_IRQ_ROOT, rp);
|
||||
}
|
||||
|
||||
static int pm8xxx_read_master_irq(const struct pm_irq_chip *chip, u8 m, u8 *bp)
|
||||
{
|
||||
return pm8xxx_readb(chip->dev,
|
||||
SSBI_REG_ADDR_IRQ_M_STATUS1 + m, bp);
|
||||
}
|
||||
|
||||
static int pm8xxx_read_block_irq(struct pm_irq_chip *chip, u8 bp, u8 *ip)
|
||||
{
|
||||
int rc;
|
||||
|
||||
spin_lock(&chip->pm_irq_lock);
|
||||
rc = pm8xxx_writeb(chip->dev, SSBI_REG_ADDR_IRQ_BLK_SEL, bp);
|
||||
if (rc) {
|
||||
pr_err("Failed Selecting Block %d rc=%d\n", bp, rc);
|
||||
goto bail;
|
||||
}
|
||||
|
||||
rc = pm8xxx_readb(chip->dev, SSBI_REG_ADDR_IRQ_IT_STATUS, ip);
|
||||
if (rc)
|
||||
pr_err("Failed Reading Status rc=%d\n", rc);
|
||||
bail:
|
||||
spin_unlock(&chip->pm_irq_lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int pm8xxx_config_irq(struct pm_irq_chip *chip, u8 bp, u8 cp)
|
||||
{
|
||||
int rc;
|
||||
|
||||
spin_lock(&chip->pm_irq_lock);
|
||||
rc = pm8xxx_writeb(chip->dev, SSBI_REG_ADDR_IRQ_BLK_SEL, bp);
|
||||
if (rc) {
|
||||
pr_err("Failed Selecting Block %d rc=%d\n", bp, rc);
|
||||
goto bail;
|
||||
}
|
||||
|
||||
cp |= PM_IRQF_WRITE;
|
||||
rc = pm8xxx_writeb(chip->dev, SSBI_REG_ADDR_IRQ_CONFIG, cp);
|
||||
if (rc)
|
||||
pr_err("Failed Configuring IRQ rc=%d\n", rc);
|
||||
bail:
|
||||
spin_unlock(&chip->pm_irq_lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int pm8xxx_irq_block_handler(struct pm_irq_chip *chip, int block)
|
||||
{
|
||||
int pmirq, irq, i, ret = 0;
|
||||
u8 bits;
|
||||
|
||||
ret = pm8xxx_read_block_irq(chip, block, &bits);
|
||||
if (ret) {
|
||||
pr_err("Failed reading %d block ret=%d", block, ret);
|
||||
return ret;
|
||||
}
|
||||
if (!bits) {
|
||||
pr_err("block bit set in master but no irqs: %d", block);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check IRQ bits */
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (bits & (1 << i)) {
|
||||
pmirq = block * 8 + i;
|
||||
irq = pmirq + chip->irq_base;
|
||||
generic_handle_irq(irq);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pm8xxx_irq_master_handler(struct pm_irq_chip *chip, int master)
|
||||
{
|
||||
u8 blockbits;
|
||||
int block_number, i, ret = 0;
|
||||
|
||||
ret = pm8xxx_read_master_irq(chip, master, &blockbits);
|
||||
if (ret) {
|
||||
pr_err("Failed to read master %d ret=%d\n", master, ret);
|
||||
return ret;
|
||||
}
|
||||
if (!blockbits) {
|
||||
pr_err("master bit set in root but no blocks: %d", master);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
if (blockbits & (1 << i)) {
|
||||
block_number = master * 8 + i; /* block # */
|
||||
ret |= pm8xxx_irq_block_handler(chip, block_number);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void pm8xxx_irq_handler(unsigned int irq, struct irq_desc *desc)
|
||||
{
|
||||
struct pm_irq_chip *chip = irq_desc_get_handler_data(desc);
|
||||
struct irq_chip *irq_chip = irq_desc_get_chip(desc);
|
||||
u8 root;
|
||||
int i, ret, masters = 0;
|
||||
|
||||
ret = pm8xxx_read_root_irq(chip, &root);
|
||||
if (ret) {
|
||||
pr_err("Can't read root status ret=%d\n", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
/* on pm8xxx series masters start from bit 1 of the root */
|
||||
masters = root >> 1;
|
||||
|
||||
/* Read allowed masters for blocks. */
|
||||
for (i = 0; i < chip->num_masters; i++)
|
||||
if (masters & (1 << i))
|
||||
pm8xxx_irq_master_handler(chip, i);
|
||||
|
||||
irq_chip->irq_ack(&desc->irq_data);
|
||||
}
|
||||
|
||||
static void pm8xxx_irq_mask_ack(struct irq_data *d)
|
||||
{
|
||||
struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d);
|
||||
unsigned int pmirq = d->irq - chip->irq_base;
|
||||
int master, irq_bit;
|
||||
u8 block, config;
|
||||
|
||||
block = pmirq / 8;
|
||||
master = block / 8;
|
||||
irq_bit = pmirq % 8;
|
||||
|
||||
config = chip->config[pmirq] | PM_IRQF_MASK_ALL | PM_IRQF_CLR;
|
||||
pm8xxx_config_irq(chip, block, config);
|
||||
}
|
||||
|
||||
static void pm8xxx_irq_unmask(struct irq_data *d)
|
||||
{
|
||||
struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d);
|
||||
unsigned int pmirq = d->irq - chip->irq_base;
|
||||
int master, irq_bit;
|
||||
u8 block, config;
|
||||
|
||||
block = pmirq / 8;
|
||||
master = block / 8;
|
||||
irq_bit = pmirq % 8;
|
||||
|
||||
config = chip->config[pmirq];
|
||||
pm8xxx_config_irq(chip, block, config);
|
||||
}
|
||||
|
||||
static int pm8xxx_irq_set_type(struct irq_data *d, unsigned int flow_type)
|
||||
{
|
||||
struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d);
|
||||
unsigned int pmirq = d->irq - chip->irq_base;
|
||||
int master, irq_bit;
|
||||
u8 block, config;
|
||||
|
||||
block = pmirq / 8;
|
||||
master = block / 8;
|
||||
irq_bit = pmirq % 8;
|
||||
|
||||
chip->config[pmirq] = (irq_bit << PM_IRQF_BITS_SHIFT)
|
||||
| PM_IRQF_MASK_ALL;
|
||||
if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) {
|
||||
if (flow_type & IRQF_TRIGGER_RISING)
|
||||
chip->config[pmirq] &= ~PM_IRQF_MASK_RE;
|
||||
if (flow_type & IRQF_TRIGGER_FALLING)
|
||||
chip->config[pmirq] &= ~PM_IRQF_MASK_FE;
|
||||
} else {
|
||||
chip->config[pmirq] |= PM_IRQF_LVL_SEL;
|
||||
|
||||
if (flow_type & IRQF_TRIGGER_HIGH)
|
||||
chip->config[pmirq] &= ~PM_IRQF_MASK_RE;
|
||||
else
|
||||
chip->config[pmirq] &= ~PM_IRQF_MASK_FE;
|
||||
}
|
||||
|
||||
config = chip->config[pmirq] | PM_IRQF_CLR;
|
||||
return pm8xxx_config_irq(chip, block, config);
|
||||
}
|
||||
|
||||
static int pm8xxx_irq_set_wake(struct irq_data *d, unsigned int on)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct irq_chip pm8xxx_irq_chip = {
|
||||
.name = "pm8xxx",
|
||||
.irq_mask_ack = pm8xxx_irq_mask_ack,
|
||||
.irq_unmask = pm8xxx_irq_unmask,
|
||||
.irq_set_type = pm8xxx_irq_set_type,
|
||||
.irq_set_wake = pm8xxx_irq_set_wake,
|
||||
.flags = IRQCHIP_MASK_ON_SUSPEND,
|
||||
};
|
||||
|
||||
/**
|
||||
* pm8xxx_get_irq_stat - get the status of the irq line
|
||||
* @chip: pointer to identify a pmic irq controller
|
||||
* @irq: the irq number
|
||||
*
|
||||
* The pm8xxx gpio and mpp rely on the interrupt block to read
|
||||
* the values on their pins. This function is to facilitate reading
|
||||
* the status of a gpio or an mpp line. The caller has to convert the
|
||||
* gpio number to irq number.
|
||||
*
|
||||
* RETURNS:
|
||||
* an int indicating the value read on that line
|
||||
*/
|
||||
int pm8xxx_get_irq_stat(struct pm_irq_chip *chip, int irq)
|
||||
{
|
||||
int pmirq, rc;
|
||||
u8 block, bits, bit;
|
||||
unsigned long flags;
|
||||
|
||||
if (chip == NULL || irq < chip->irq_base ||
|
||||
irq >= chip->irq_base + chip->num_irqs)
|
||||
return -EINVAL;
|
||||
|
||||
pmirq = irq - chip->irq_base;
|
||||
|
||||
block = pmirq / 8;
|
||||
bit = pmirq % 8;
|
||||
|
||||
spin_lock_irqsave(&chip->pm_irq_lock, flags);
|
||||
|
||||
rc = pm8xxx_writeb(chip->dev, SSBI_REG_ADDR_IRQ_BLK_SEL, block);
|
||||
if (rc) {
|
||||
pr_err("Failed Selecting block irq=%d pmirq=%d blk=%d rc=%d\n",
|
||||
irq, pmirq, block, rc);
|
||||
goto bail_out;
|
||||
}
|
||||
|
||||
rc = pm8xxx_readb(chip->dev, SSBI_REG_ADDR_IRQ_RT_STATUS, &bits);
|
||||
if (rc) {
|
||||
pr_err("Failed Configuring irq=%d pmirq=%d blk=%d rc=%d\n",
|
||||
irq, pmirq, block, rc);
|
||||
goto bail_out;
|
||||
}
|
||||
|
||||
rc = (bits & (1 << bit)) ? 1 : 0;
|
||||
|
||||
bail_out:
|
||||
spin_unlock_irqrestore(&chip->pm_irq_lock, flags);
|
||||
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pm8xxx_get_irq_stat);
|
||||
|
||||
struct pm_irq_chip * __devinit pm8xxx_irq_init(struct device *dev,
|
||||
const struct pm8xxx_irq_platform_data *pdata)
|
||||
{
|
||||
struct pm_irq_chip *chip;
|
||||
int devirq, rc;
|
||||
unsigned int pmirq;
|
||||
|
||||
if (!pdata) {
|
||||
pr_err("No platform data\n");
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
devirq = pdata->devirq;
|
||||
if (devirq < 0) {
|
||||
pr_err("missing devirq\n");
|
||||
rc = devirq;
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
chip = kzalloc(sizeof(struct pm_irq_chip)
|
||||
+ sizeof(u8) * pdata->irq_cdata.nirqs, GFP_KERNEL);
|
||||
if (!chip) {
|
||||
pr_err("Cannot alloc pm_irq_chip struct\n");
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
chip->dev = dev;
|
||||
chip->devirq = devirq;
|
||||
chip->irq_base = pdata->irq_base;
|
||||
chip->num_irqs = pdata->irq_cdata.nirqs;
|
||||
chip->num_blocks = DIV_ROUND_UP(chip->num_irqs, 8);
|
||||
chip->num_masters = DIV_ROUND_UP(chip->num_blocks, 8);
|
||||
spin_lock_init(&chip->pm_irq_lock);
|
||||
|
||||
for (pmirq = 0; pmirq < chip->num_irqs; pmirq++) {
|
||||
irq_set_chip_and_handler(chip->irq_base + pmirq,
|
||||
&pm8xxx_irq_chip,
|
||||
handle_level_irq);
|
||||
irq_set_chip_data(chip->irq_base + pmirq, chip);
|
||||
#ifdef CONFIG_ARM
|
||||
set_irq_flags(chip->irq_base + pmirq, IRQF_VALID);
|
||||
#else
|
||||
irq_set_noprobe(chip->irq_base + pmirq);
|
||||
#endif
|
||||
}
|
||||
|
||||
irq_set_irq_type(devirq, pdata->irq_trigger_flag);
|
||||
irq_set_handler_data(devirq, chip);
|
||||
irq_set_chained_handler(devirq, pm8xxx_irq_handler);
|
||||
set_irq_wake(devirq, 1);
|
||||
|
||||
return chip;
|
||||
}
|
||||
|
||||
int __devexit pm8xxx_irq_exit(struct pm_irq_chip *chip)
|
||||
{
|
||||
irq_set_chained_handler(chip->devirq, NULL);
|
||||
kfree(chip);
|
||||
return 0;
|
||||
}
|
@ -61,12 +61,14 @@ static struct mfd_cell rdc321x_sb_cells[] = {
|
||||
.name = "rdc321x-wdt",
|
||||
.resources = rdc321x_wdt_resource,
|
||||
.num_resources = ARRAY_SIZE(rdc321x_wdt_resource),
|
||||
.mfd_data = &rdc321x_wdt_pdata,
|
||||
.platform_data = &rdc321x_wdt_pdata,
|
||||
.pdata_size = sizeof(rdc321x_wdt_pdata),
|
||||
}, {
|
||||
.name = "rdc321x-gpio",
|
||||
.resources = rdc321x_gpio_resources,
|
||||
.num_resources = ARRAY_SIZE(rdc321x_gpio_resources),
|
||||
.mfd_data = &rdc321x_gpio_pdata,
|
||||
.platform_data = &rdc321x_gpio_pdata,
|
||||
.pdata_size = sizeof(rdc321x_gpio_pdata),
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -170,7 +170,8 @@ static struct mfd_cell t7l66xb_cells[] = {
|
||||
.name = "tmio-mmc",
|
||||
.enable = t7l66xb_mmc_enable,
|
||||
.disable = t7l66xb_mmc_disable,
|
||||
.mfd_data = &t7166xb_mmc_data,
|
||||
.platform_data = &t7166xb_mmc_data,
|
||||
.pdata_size = sizeof(t7166xb_mmc_data),
|
||||
.num_resources = ARRAY_SIZE(t7l66xb_mmc_resources),
|
||||
.resources = t7l66xb_mmc_resources,
|
||||
},
|
||||
@ -382,7 +383,8 @@ static int t7l66xb_probe(struct platform_device *dev)
|
||||
|
||||
t7l66xb_attach_irq(dev);
|
||||
|
||||
t7l66xb_cells[T7L66XB_CELL_NAND].mfd_data = pdata->nand_data;
|
||||
t7l66xb_cells[T7L66XB_CELL_NAND].platform_data = pdata->nand_data;
|
||||
t7l66xb_cells[T7L66XB_CELL_NAND].pdata_size = sizeof(*pdata->nand_data);
|
||||
|
||||
ret = mfd_add_devices(&dev->dev, dev->id,
|
||||
t7l66xb_cells, ARRAY_SIZE(t7l66xb_cells),
|
||||
|
@ -131,7 +131,8 @@ static struct mfd_cell tc6387xb_cells[] = {
|
||||
.name = "tmio-mmc",
|
||||
.enable = tc6387xb_mmc_enable,
|
||||
.disable = tc6387xb_mmc_disable,
|
||||
.mfd_data = &tc6387xb_mmc_data,
|
||||
.platform_data = &tc6387xb_mmc_data,
|
||||
.pdata_size = sizeof(tc6387xb_mmc_data),
|
||||
.num_resources = ARRAY_SIZE(tc6387xb_mmc_resources),
|
||||
.resources = tc6387xb_mmc_resources,
|
||||
},
|
||||
|
@ -393,7 +393,8 @@ static struct mfd_cell __devinitdata tc6393xb_cells[] = {
|
||||
.name = "tmio-mmc",
|
||||
.enable = tc6393xb_mmc_enable,
|
||||
.resume = tc6393xb_mmc_resume,
|
||||
.mfd_data = &tc6393xb_mmc_data,
|
||||
.platform_data = &tc6393xb_mmc_data,
|
||||
.pdata_size = sizeof(tc6393xb_mmc_data),
|
||||
.num_resources = ARRAY_SIZE(tc6393xb_mmc_resources),
|
||||
.resources = tc6393xb_mmc_resources,
|
||||
},
|
||||
@ -692,8 +693,11 @@ static int __devinit tc6393xb_probe(struct platform_device *dev)
|
||||
goto err_setup;
|
||||
}
|
||||
|
||||
tc6393xb_cells[TC6393XB_CELL_NAND].mfd_data = tcpd->nand_data;
|
||||
tc6393xb_cells[TC6393XB_CELL_FB].mfd_data = tcpd->fb_data;
|
||||
tc6393xb_cells[TC6393XB_CELL_NAND].platform_data = tcpd->nand_data;
|
||||
tc6393xb_cells[TC6393XB_CELL_NAND].pdata_size =
|
||||
sizeof(*tcpd->nand_data);
|
||||
tc6393xb_cells[TC6393XB_CELL_FB].platform_data = tcpd->fb_data;
|
||||
tc6393xb_cells[TC6393XB_CELL_FB].pdata_size = sizeof(*tcpd->fb_data);
|
||||
|
||||
ret = mfd_add_devices(&dev->dev, dev->id,
|
||||
tc6393xb_cells, ARRAY_SIZE(tc6393xb_cells),
|
||||
|
@ -384,7 +384,8 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg0[] = {
|
||||
.name = "timb-dma",
|
||||
.num_resources = ARRAY_SIZE(timberdale_dma_resources),
|
||||
.resources = timberdale_dma_resources,
|
||||
.mfd_data = &timb_dma_platform_data,
|
||||
.platform_data = &timb_dma_platform_data,
|
||||
.pdata_size = sizeof(timb_dma_platform_data),
|
||||
},
|
||||
{
|
||||
.name = "timb-uart",
|
||||
@ -395,37 +396,43 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg0[] = {
|
||||
.name = "xiic-i2c",
|
||||
.num_resources = ARRAY_SIZE(timberdale_xiic_resources),
|
||||
.resources = timberdale_xiic_resources,
|
||||
.mfd_data = &timberdale_xiic_platform_data,
|
||||
.platform_data = &timberdale_xiic_platform_data,
|
||||
.pdata_size = sizeof(timberdale_xiic_platform_data),
|
||||
},
|
||||
{
|
||||
.name = "timb-gpio",
|
||||
.num_resources = ARRAY_SIZE(timberdale_gpio_resources),
|
||||
.resources = timberdale_gpio_resources,
|
||||
.mfd_data = &timberdale_gpio_platform_data,
|
||||
.platform_data = &timberdale_gpio_platform_data,
|
||||
.pdata_size = sizeof(timberdale_gpio_platform_data),
|
||||
},
|
||||
{
|
||||
.name = "timb-video",
|
||||
.num_resources = ARRAY_SIZE(timberdale_video_resources),
|
||||
.resources = timberdale_video_resources,
|
||||
.mfd_data = &timberdale_video_platform_data,
|
||||
.platform_data = &timberdale_video_platform_data,
|
||||
.pdata_size = sizeof(timberdale_video_platform_data),
|
||||
},
|
||||
{
|
||||
.name = "timb-radio",
|
||||
.num_resources = ARRAY_SIZE(timberdale_radio_resources),
|
||||
.resources = timberdale_radio_resources,
|
||||
.mfd_data = &timberdale_radio_platform_data,
|
||||
.platform_data = &timberdale_radio_platform_data,
|
||||
.pdata_size = sizeof(timberdale_radio_platform_data),
|
||||
},
|
||||
{
|
||||
.name = "xilinx_spi",
|
||||
.num_resources = ARRAY_SIZE(timberdale_spi_resources),
|
||||
.resources = timberdale_spi_resources,
|
||||
.mfd_data = &timberdale_xspi_platform_data,
|
||||
.platform_data = &timberdale_xspi_platform_data,
|
||||
.pdata_size = sizeof(timberdale_xspi_platform_data),
|
||||
},
|
||||
{
|
||||
.name = "ks8842",
|
||||
.num_resources = ARRAY_SIZE(timberdale_eth_resources),
|
||||
.resources = timberdale_eth_resources,
|
||||
.mfd_data = &timberdale_ks8842_platform_data,
|
||||
.platform_data = &timberdale_ks8842_platform_data,
|
||||
.pdata_size = sizeof(timberdale_ks8842_platform_data),
|
||||
},
|
||||
};
|
||||
|
||||
@ -434,7 +441,8 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg1[] = {
|
||||
.name = "timb-dma",
|
||||
.num_resources = ARRAY_SIZE(timberdale_dma_resources),
|
||||
.resources = timberdale_dma_resources,
|
||||
.mfd_data = &timb_dma_platform_data,
|
||||
.platform_data = &timb_dma_platform_data,
|
||||
.pdata_size = sizeof(timb_dma_platform_data),
|
||||
},
|
||||
{
|
||||
.name = "timb-uart",
|
||||
@ -450,13 +458,15 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg1[] = {
|
||||
.name = "xiic-i2c",
|
||||
.num_resources = ARRAY_SIZE(timberdale_xiic_resources),
|
||||
.resources = timberdale_xiic_resources,
|
||||
.mfd_data = &timberdale_xiic_platform_data,
|
||||
.platform_data = &timberdale_xiic_platform_data,
|
||||
.pdata_size = sizeof(timberdale_xiic_platform_data),
|
||||
},
|
||||
{
|
||||
.name = "timb-gpio",
|
||||
.num_resources = ARRAY_SIZE(timberdale_gpio_resources),
|
||||
.resources = timberdale_gpio_resources,
|
||||
.mfd_data = &timberdale_gpio_platform_data,
|
||||
.platform_data = &timberdale_gpio_platform_data,
|
||||
.pdata_size = sizeof(timberdale_gpio_platform_data),
|
||||
},
|
||||
{
|
||||
.name = "timb-mlogicore",
|
||||
@ -467,25 +477,29 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg1[] = {
|
||||
.name = "timb-video",
|
||||
.num_resources = ARRAY_SIZE(timberdale_video_resources),
|
||||
.resources = timberdale_video_resources,
|
||||
.mfd_data = &timberdale_video_platform_data,
|
||||
.platform_data = &timberdale_video_platform_data,
|
||||
.pdata_size = sizeof(timberdale_video_platform_data),
|
||||
},
|
||||
{
|
||||
.name = "timb-radio",
|
||||
.num_resources = ARRAY_SIZE(timberdale_radio_resources),
|
||||
.resources = timberdale_radio_resources,
|
||||
.mfd_data = &timberdale_radio_platform_data,
|
||||
.platform_data = &timberdale_radio_platform_data,
|
||||
.pdata_size = sizeof(timberdale_radio_platform_data),
|
||||
},
|
||||
{
|
||||
.name = "xilinx_spi",
|
||||
.num_resources = ARRAY_SIZE(timberdale_spi_resources),
|
||||
.resources = timberdale_spi_resources,
|
||||
.mfd_data = &timberdale_xspi_platform_data,
|
||||
.platform_data = &timberdale_xspi_platform_data,
|
||||
.pdata_size = sizeof(timberdale_xspi_platform_data),
|
||||
},
|
||||
{
|
||||
.name = "ks8842",
|
||||
.num_resources = ARRAY_SIZE(timberdale_eth_resources),
|
||||
.resources = timberdale_eth_resources,
|
||||
.mfd_data = &timberdale_ks8842_platform_data,
|
||||
.platform_data = &timberdale_ks8842_platform_data,
|
||||
.pdata_size = sizeof(timberdale_ks8842_platform_data),
|
||||
},
|
||||
};
|
||||
|
||||
@ -494,7 +508,8 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg2[] = {
|
||||
.name = "timb-dma",
|
||||
.num_resources = ARRAY_SIZE(timberdale_dma_resources),
|
||||
.resources = timberdale_dma_resources,
|
||||
.mfd_data = &timb_dma_platform_data,
|
||||
.platform_data = &timb_dma_platform_data,
|
||||
.pdata_size = sizeof(timb_dma_platform_data),
|
||||
},
|
||||
{
|
||||
.name = "timb-uart",
|
||||
@ -505,31 +520,36 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg2[] = {
|
||||
.name = "xiic-i2c",
|
||||
.num_resources = ARRAY_SIZE(timberdale_xiic_resources),
|
||||
.resources = timberdale_xiic_resources,
|
||||
.mfd_data = &timberdale_xiic_platform_data,
|
||||
.platform_data = &timberdale_xiic_platform_data,
|
||||
.pdata_size = sizeof(timberdale_xiic_platform_data),
|
||||
},
|
||||
{
|
||||
.name = "timb-gpio",
|
||||
.num_resources = ARRAY_SIZE(timberdale_gpio_resources),
|
||||
.resources = timberdale_gpio_resources,
|
||||
.mfd_data = &timberdale_gpio_platform_data,
|
||||
.platform_data = &timberdale_gpio_platform_data,
|
||||
.pdata_size = sizeof(timberdale_gpio_platform_data),
|
||||
},
|
||||
{
|
||||
.name = "timb-video",
|
||||
.num_resources = ARRAY_SIZE(timberdale_video_resources),
|
||||
.resources = timberdale_video_resources,
|
||||
.mfd_data = &timberdale_video_platform_data,
|
||||
.platform_data = &timberdale_video_platform_data,
|
||||
.pdata_size = sizeof(timberdale_video_platform_data),
|
||||
},
|
||||
{
|
||||
.name = "timb-radio",
|
||||
.num_resources = ARRAY_SIZE(timberdale_radio_resources),
|
||||
.resources = timberdale_radio_resources,
|
||||
.mfd_data = &timberdale_radio_platform_data,
|
||||
.platform_data = &timberdale_radio_platform_data,
|
||||
.pdata_size = sizeof(timberdale_radio_platform_data),
|
||||
},
|
||||
{
|
||||
.name = "xilinx_spi",
|
||||
.num_resources = ARRAY_SIZE(timberdale_spi_resources),
|
||||
.resources = timberdale_spi_resources,
|
||||
.mfd_data = &timberdale_xspi_platform_data,
|
||||
.platform_data = &timberdale_xspi_platform_data,
|
||||
.pdata_size = sizeof(timberdale_xspi_platform_data),
|
||||
},
|
||||
};
|
||||
|
||||
@ -538,7 +558,8 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg3[] = {
|
||||
.name = "timb-dma",
|
||||
.num_resources = ARRAY_SIZE(timberdale_dma_resources),
|
||||
.resources = timberdale_dma_resources,
|
||||
.mfd_data = &timb_dma_platform_data,
|
||||
.platform_data = &timb_dma_platform_data,
|
||||
.pdata_size = sizeof(timb_dma_platform_data),
|
||||
},
|
||||
{
|
||||
.name = "timb-uart",
|
||||
@ -549,37 +570,43 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg3[] = {
|
||||
.name = "ocores-i2c",
|
||||
.num_resources = ARRAY_SIZE(timberdale_ocores_resources),
|
||||
.resources = timberdale_ocores_resources,
|
||||
.mfd_data = &timberdale_ocores_platform_data,
|
||||
.platform_data = &timberdale_ocores_platform_data,
|
||||
.pdata_size = sizeof(timberdale_ocores_platform_data),
|
||||
},
|
||||
{
|
||||
.name = "timb-gpio",
|
||||
.num_resources = ARRAY_SIZE(timberdale_gpio_resources),
|
||||
.resources = timberdale_gpio_resources,
|
||||
.mfd_data = &timberdale_gpio_platform_data,
|
||||
.platform_data = &timberdale_gpio_platform_data,
|
||||
.pdata_size = sizeof(timberdale_gpio_platform_data),
|
||||
},
|
||||
{
|
||||
.name = "timb-video",
|
||||
.num_resources = ARRAY_SIZE(timberdale_video_resources),
|
||||
.resources = timberdale_video_resources,
|
||||
.mfd_data = &timberdale_video_platform_data,
|
||||
.platform_data = &timberdale_video_platform_data,
|
||||
.pdata_size = sizeof(timberdale_video_platform_data),
|
||||
},
|
||||
{
|
||||
.name = "timb-radio",
|
||||
.num_resources = ARRAY_SIZE(timberdale_radio_resources),
|
||||
.resources = timberdale_radio_resources,
|
||||
.mfd_data = &timberdale_radio_platform_data,
|
||||
.platform_data = &timberdale_radio_platform_data,
|
||||
.pdata_size = sizeof(timberdale_radio_platform_data),
|
||||
},
|
||||
{
|
||||
.name = "xilinx_spi",
|
||||
.num_resources = ARRAY_SIZE(timberdale_spi_resources),
|
||||
.resources = timberdale_spi_resources,
|
||||
.mfd_data = &timberdale_xspi_platform_data,
|
||||
.platform_data = &timberdale_xspi_platform_data,
|
||||
.pdata_size = sizeof(timberdale_xspi_platform_data),
|
||||
},
|
||||
{
|
||||
.name = "ks8842",
|
||||
.num_resources = ARRAY_SIZE(timberdale_eth_resources),
|
||||
.resources = timberdale_eth_resources,
|
||||
.mfd_data = &timberdale_ks8842_platform_data,
|
||||
.platform_data = &timberdale_ks8842_platform_data,
|
||||
.pdata_size = sizeof(timberdale_ks8842_platform_data),
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -183,7 +183,8 @@ static int __devinit tps6105x_probe(struct i2c_client *client,
|
||||
/* Set up and register the platform devices. */
|
||||
for (i = 0; i < ARRAY_SIZE(tps6105x_cells); i++) {
|
||||
/* One state holder for all drivers, this is simple */
|
||||
tps6105x_cells[i].mfd_data = tps6105x;
|
||||
tps6105x_cells[i].platform_data = tps6105x;
|
||||
tps6105x_cells[i].pdata_size = sizeof(*tps6105x);
|
||||
}
|
||||
|
||||
ret = mfd_add_devices(&client->dev, 0, tps6105x_cells,
|
||||
|
@ -270,8 +270,8 @@ static void tps6586x_gpio_set(struct gpio_chip *chip, unsigned offset,
|
||||
{
|
||||
struct tps6586x *tps6586x = container_of(chip, struct tps6586x, gpio);
|
||||
|
||||
__tps6586x_write(tps6586x->client, TPS6586X_GPIOSET2,
|
||||
value << offset);
|
||||
tps6586x_update(tps6586x->dev, TPS6586X_GPIOSET2,
|
||||
value << offset, 1 << offset);
|
||||
}
|
||||
|
||||
static int tps6586x_gpio_output(struct gpio_chip *gc, unsigned offset,
|
||||
|
@ -198,6 +198,7 @@
|
||||
#define TWL6030_BASEADD_GASGAUGE 0x00C0
|
||||
#define TWL6030_BASEADD_PIH 0x00D0
|
||||
#define TWL6030_BASEADD_CHARGER 0x00E0
|
||||
#define TWL6025_BASEADD_CHARGER 0x00DA
|
||||
|
||||
/* subchip/slave 2 0x4A - DFT */
|
||||
#define TWL6030_BASEADD_DIEID 0x00C0
|
||||
@ -229,6 +230,9 @@
|
||||
/* is driver active, bound to a chip? */
|
||||
static bool inuse;
|
||||
|
||||
/* TWL IDCODE Register value */
|
||||
static u32 twl_idcode;
|
||||
|
||||
static unsigned int twl_id;
|
||||
unsigned int twl_rev(void)
|
||||
{
|
||||
@ -328,6 +332,7 @@ static struct twl_mapping twl6030_map[] = {
|
||||
|
||||
{ SUB_CHIP_ID0, TWL6030_BASEADD_RTC },
|
||||
{ SUB_CHIP_ID0, TWL6030_BASEADD_MEM },
|
||||
{ SUB_CHIP_ID1, TWL6025_BASEADD_CHARGER },
|
||||
};
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
@ -487,6 +492,58 @@ EXPORT_SYMBOL(twl_i2c_read_u8);
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* twl_read_idcode_register - API to read the IDCODE register.
|
||||
*
|
||||
* Unlocks the IDCODE register and read the 32 bit value.
|
||||
*/
|
||||
static int twl_read_idcode_register(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = twl_i2c_write_u8(TWL4030_MODULE_INTBR, TWL_EEPROM_R_UNLOCK,
|
||||
REG_UNLOCK_TEST_REG);
|
||||
if (err) {
|
||||
pr_err("TWL4030 Unable to unlock IDCODE registers -%d\n", err);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
err = twl_i2c_read(TWL4030_MODULE_INTBR, (u8 *)(&twl_idcode),
|
||||
REG_IDCODE_7_0, 4);
|
||||
if (err) {
|
||||
pr_err("TWL4030: unable to read IDCODE -%d\n", err);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
err = twl_i2c_write_u8(TWL4030_MODULE_INTBR, 0x0, REG_UNLOCK_TEST_REG);
|
||||
if (err)
|
||||
pr_err("TWL4030 Unable to relock IDCODE registers -%d\n", err);
|
||||
fail:
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* twl_get_type - API to get TWL Si type.
|
||||
*
|
||||
* Api to get the TWL Si type from IDCODE value.
|
||||
*/
|
||||
int twl_get_type(void)
|
||||
{
|
||||
return TWL_SIL_TYPE(twl_idcode);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(twl_get_type);
|
||||
|
||||
/**
|
||||
* twl_get_version - API to get TWL Si version.
|
||||
*
|
||||
* Api to get the TWL Si version from IDCODE value.
|
||||
*/
|
||||
int twl_get_version(void)
|
||||
{
|
||||
return TWL_SIL_REV(twl_idcode);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(twl_get_version);
|
||||
|
||||
static struct device *
|
||||
add_numbered_child(unsigned chip, const char *name, int num,
|
||||
void *pdata, unsigned pdata_len,
|
||||
@ -549,7 +606,7 @@ static inline struct device *add_child(unsigned chip, const char *name,
|
||||
static struct device *
|
||||
add_regulator_linked(int num, struct regulator_init_data *pdata,
|
||||
struct regulator_consumer_supply *consumers,
|
||||
unsigned num_consumers)
|
||||
unsigned num_consumers, unsigned long features)
|
||||
{
|
||||
unsigned sub_chip_id;
|
||||
/* regulator framework demands init_data ... */
|
||||
@ -561,6 +618,8 @@ add_regulator_linked(int num, struct regulator_init_data *pdata,
|
||||
pdata->num_consumer_supplies = num_consumers;
|
||||
}
|
||||
|
||||
pdata->driver_data = (void *)features;
|
||||
|
||||
/* NOTE: we currently ignore regulator IRQs, e.g. for short circuits */
|
||||
sub_chip_id = twl_map[TWL_MODULE_PM_MASTER].sid;
|
||||
return add_numbered_child(sub_chip_id, "twl_reg", num,
|
||||
@ -568,9 +627,10 @@ add_regulator_linked(int num, struct regulator_init_data *pdata,
|
||||
}
|
||||
|
||||
static struct device *
|
||||
add_regulator(int num, struct regulator_init_data *pdata)
|
||||
add_regulator(int num, struct regulator_init_data *pdata,
|
||||
unsigned long features)
|
||||
{
|
||||
return add_regulator_linked(num, pdata, NULL, 0);
|
||||
return add_regulator_linked(num, pdata, NULL, 0, features);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -650,17 +710,20 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
|
||||
};
|
||||
|
||||
child = add_regulator_linked(TWL4030_REG_VUSB1V5,
|
||||
&usb_fixed, &usb1v5, 1);
|
||||
&usb_fixed, &usb1v5, 1,
|
||||
features);
|
||||
if (IS_ERR(child))
|
||||
return PTR_ERR(child);
|
||||
|
||||
child = add_regulator_linked(TWL4030_REG_VUSB1V8,
|
||||
&usb_fixed, &usb1v8, 1);
|
||||
&usb_fixed, &usb1v8, 1,
|
||||
features);
|
||||
if (IS_ERR(child))
|
||||
return PTR_ERR(child);
|
||||
|
||||
child = add_regulator_linked(TWL4030_REG_VUSB3V1,
|
||||
&usb_fixed, &usb3v1, 1);
|
||||
&usb_fixed, &usb3v1, 1,
|
||||
features);
|
||||
if (IS_ERR(child))
|
||||
return PTR_ERR(child);
|
||||
|
||||
@ -685,9 +748,8 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
|
||||
}
|
||||
if (twl_has_usb() && pdata->usb && twl_class_is_6030()) {
|
||||
|
||||
static struct regulator_consumer_supply usb3v3 = {
|
||||
.supply = "vusb",
|
||||
};
|
||||
static struct regulator_consumer_supply usb3v3;
|
||||
int regulator;
|
||||
|
||||
if (twl_has_regulator()) {
|
||||
/* this is a template that gets copied */
|
||||
@ -700,12 +762,22 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
|
||||
| REGULATOR_CHANGE_STATUS,
|
||||
};
|
||||
|
||||
child = add_regulator_linked(TWL6030_REG_VUSB,
|
||||
&usb_fixed, &usb3v3, 1);
|
||||
if (features & TWL6025_SUBCLASS) {
|
||||
usb3v3.supply = "ldousb";
|
||||
regulator = TWL6025_REG_LDOUSB;
|
||||
} else {
|
||||
usb3v3.supply = "vusb";
|
||||
regulator = TWL6030_REG_VUSB;
|
||||
}
|
||||
child = add_regulator_linked(regulator, &usb_fixed,
|
||||
&usb3v3, 1,
|
||||
features);
|
||||
if (IS_ERR(child))
|
||||
return PTR_ERR(child);
|
||||
}
|
||||
|
||||
pdata->usb->features = features;
|
||||
|
||||
child = add_child(0, "twl6030_usb",
|
||||
pdata->usb, sizeof(*pdata->usb),
|
||||
true,
|
||||
@ -718,7 +790,16 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
|
||||
/* we need to connect regulators to this transceiver */
|
||||
if (twl_has_regulator() && child)
|
||||
usb3v3.dev = child;
|
||||
} else if (twl_has_regulator() && twl_class_is_6030()) {
|
||||
if (features & TWL6025_SUBCLASS)
|
||||
child = add_regulator(TWL6025_REG_LDOUSB,
|
||||
pdata->ldousb, features);
|
||||
else
|
||||
child = add_regulator(TWL6030_REG_VUSB,
|
||||
pdata->vusb, features);
|
||||
|
||||
if (IS_ERR(child))
|
||||
return PTR_ERR(child);
|
||||
}
|
||||
|
||||
if (twl_has_watchdog() && twl_class_is_4030()) {
|
||||
@ -755,46 +836,55 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
|
||||
|
||||
/* twl4030 regulators */
|
||||
if (twl_has_regulator() && twl_class_is_4030()) {
|
||||
child = add_regulator(TWL4030_REG_VPLL1, pdata->vpll1);
|
||||
child = add_regulator(TWL4030_REG_VPLL1, pdata->vpll1,
|
||||
features);
|
||||
if (IS_ERR(child))
|
||||
return PTR_ERR(child);
|
||||
|
||||
child = add_regulator(TWL4030_REG_VIO, pdata->vio);
|
||||
child = add_regulator(TWL4030_REG_VIO, pdata->vio,
|
||||
features);
|
||||
if (IS_ERR(child))
|
||||
return PTR_ERR(child);
|
||||
|
||||
child = add_regulator(TWL4030_REG_VDD1, pdata->vdd1);
|
||||
child = add_regulator(TWL4030_REG_VDD1, pdata->vdd1,
|
||||
features);
|
||||
if (IS_ERR(child))
|
||||
return PTR_ERR(child);
|
||||
|
||||
child = add_regulator(TWL4030_REG_VDD2, pdata->vdd2);
|
||||
child = add_regulator(TWL4030_REG_VDD2, pdata->vdd2,
|
||||
features);
|
||||
if (IS_ERR(child))
|
||||
return PTR_ERR(child);
|
||||
|
||||
child = add_regulator(TWL4030_REG_VMMC1, pdata->vmmc1);
|
||||
child = add_regulator(TWL4030_REG_VMMC1, pdata->vmmc1,
|
||||
features);
|
||||
if (IS_ERR(child))
|
||||
return PTR_ERR(child);
|
||||
|
||||
child = add_regulator(TWL4030_REG_VDAC, pdata->vdac);
|
||||
child = add_regulator(TWL4030_REG_VDAC, pdata->vdac,
|
||||
features);
|
||||
if (IS_ERR(child))
|
||||
return PTR_ERR(child);
|
||||
|
||||
child = add_regulator((features & TWL4030_VAUX2)
|
||||
? TWL4030_REG_VAUX2_4030
|
||||
: TWL4030_REG_VAUX2,
|
||||
pdata->vaux2);
|
||||
pdata->vaux2, features);
|
||||
if (IS_ERR(child))
|
||||
return PTR_ERR(child);
|
||||
|
||||
child = add_regulator(TWL4030_REG_VINTANA1, pdata->vintana1);
|
||||
child = add_regulator(TWL4030_REG_VINTANA1, pdata->vintana1,
|
||||
features);
|
||||
if (IS_ERR(child))
|
||||
return PTR_ERR(child);
|
||||
|
||||
child = add_regulator(TWL4030_REG_VINTANA2, pdata->vintana2);
|
||||
child = add_regulator(TWL4030_REG_VINTANA2, pdata->vintana2,
|
||||
features);
|
||||
if (IS_ERR(child))
|
||||
return PTR_ERR(child);
|
||||
|
||||
child = add_regulator(TWL4030_REG_VINTDIG, pdata->vintdig);
|
||||
child = add_regulator(TWL4030_REG_VINTDIG, pdata->vintdig,
|
||||
features);
|
||||
if (IS_ERR(child))
|
||||
return PTR_ERR(child);
|
||||
}
|
||||
@ -802,72 +892,152 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
|
||||
/* maybe add LDOs that are omitted on cost-reduced parts */
|
||||
if (twl_has_regulator() && !(features & TPS_SUBSET)
|
||||
&& twl_class_is_4030()) {
|
||||
child = add_regulator(TWL4030_REG_VPLL2, pdata->vpll2);
|
||||
child = add_regulator(TWL4030_REG_VPLL2, pdata->vpll2,
|
||||
features);
|
||||
if (IS_ERR(child))
|
||||
return PTR_ERR(child);
|
||||
|
||||
child = add_regulator(TWL4030_REG_VMMC2, pdata->vmmc2);
|
||||
child = add_regulator(TWL4030_REG_VMMC2, pdata->vmmc2,
|
||||
features);
|
||||
if (IS_ERR(child))
|
||||
return PTR_ERR(child);
|
||||
|
||||
child = add_regulator(TWL4030_REG_VSIM, pdata->vsim);
|
||||
child = add_regulator(TWL4030_REG_VSIM, pdata->vsim,
|
||||
features);
|
||||
if (IS_ERR(child))
|
||||
return PTR_ERR(child);
|
||||
|
||||
child = add_regulator(TWL4030_REG_VAUX1, pdata->vaux1);
|
||||
child = add_regulator(TWL4030_REG_VAUX1, pdata->vaux1,
|
||||
features);
|
||||
if (IS_ERR(child))
|
||||
return PTR_ERR(child);
|
||||
|
||||
child = add_regulator(TWL4030_REG_VAUX3, pdata->vaux3);
|
||||
child = add_regulator(TWL4030_REG_VAUX3, pdata->vaux3,
|
||||
features);
|
||||
if (IS_ERR(child))
|
||||
return PTR_ERR(child);
|
||||
|
||||
child = add_regulator(TWL4030_REG_VAUX4, pdata->vaux4);
|
||||
child = add_regulator(TWL4030_REG_VAUX4, pdata->vaux4,
|
||||
features);
|
||||
if (IS_ERR(child))
|
||||
return PTR_ERR(child);
|
||||
}
|
||||
|
||||
/* twl6030 regulators */
|
||||
if (twl_has_regulator() && twl_class_is_6030() &&
|
||||
!(features & TWL6025_SUBCLASS)) {
|
||||
child = add_regulator(TWL6030_REG_VMMC, pdata->vmmc,
|
||||
features);
|
||||
if (IS_ERR(child))
|
||||
return PTR_ERR(child);
|
||||
|
||||
child = add_regulator(TWL6030_REG_VPP, pdata->vpp,
|
||||
features);
|
||||
if (IS_ERR(child))
|
||||
return PTR_ERR(child);
|
||||
|
||||
child = add_regulator(TWL6030_REG_VUSIM, pdata->vusim,
|
||||
features);
|
||||
if (IS_ERR(child))
|
||||
return PTR_ERR(child);
|
||||
|
||||
child = add_regulator(TWL6030_REG_VCXIO, pdata->vcxio,
|
||||
features);
|
||||
if (IS_ERR(child))
|
||||
return PTR_ERR(child);
|
||||
|
||||
child = add_regulator(TWL6030_REG_VDAC, pdata->vdac,
|
||||
features);
|
||||
if (IS_ERR(child))
|
||||
return PTR_ERR(child);
|
||||
|
||||
child = add_regulator(TWL6030_REG_VAUX1_6030, pdata->vaux1,
|
||||
features);
|
||||
if (IS_ERR(child))
|
||||
return PTR_ERR(child);
|
||||
|
||||
child = add_regulator(TWL6030_REG_VAUX2_6030, pdata->vaux2,
|
||||
features);
|
||||
if (IS_ERR(child))
|
||||
return PTR_ERR(child);
|
||||
|
||||
child = add_regulator(TWL6030_REG_VAUX3_6030, pdata->vaux3,
|
||||
features);
|
||||
if (IS_ERR(child))
|
||||
return PTR_ERR(child);
|
||||
|
||||
child = add_regulator(TWL6030_REG_CLK32KG, pdata->clk32kg,
|
||||
features);
|
||||
if (IS_ERR(child))
|
||||
return PTR_ERR(child);
|
||||
}
|
||||
|
||||
/* 6030 and 6025 share this regulator */
|
||||
if (twl_has_regulator() && twl_class_is_6030()) {
|
||||
child = add_regulator(TWL6030_REG_VMMC, pdata->vmmc);
|
||||
child = add_regulator(TWL6030_REG_VANA, pdata->vana,
|
||||
features);
|
||||
if (IS_ERR(child))
|
||||
return PTR_ERR(child);
|
||||
}
|
||||
|
||||
/* twl6025 regulators */
|
||||
if (twl_has_regulator() && twl_class_is_6030() &&
|
||||
(features & TWL6025_SUBCLASS)) {
|
||||
child = add_regulator(TWL6025_REG_LDO5, pdata->ldo5,
|
||||
features);
|
||||
if (IS_ERR(child))
|
||||
return PTR_ERR(child);
|
||||
|
||||
child = add_regulator(TWL6030_REG_VPP, pdata->vpp);
|
||||
child = add_regulator(TWL6025_REG_LDO1, pdata->ldo1,
|
||||
features);
|
||||
if (IS_ERR(child))
|
||||
return PTR_ERR(child);
|
||||
|
||||
child = add_regulator(TWL6030_REG_VUSIM, pdata->vusim);
|
||||
child = add_regulator(TWL6025_REG_LDO7, pdata->ldo7,
|
||||
features);
|
||||
if (IS_ERR(child))
|
||||
return PTR_ERR(child);
|
||||
|
||||
child = add_regulator(TWL6030_REG_VANA, pdata->vana);
|
||||
child = add_regulator(TWL6025_REG_LDO6, pdata->ldo6,
|
||||
features);
|
||||
if (IS_ERR(child))
|
||||
return PTR_ERR(child);
|
||||
|
||||
child = add_regulator(TWL6030_REG_VCXIO, pdata->vcxio);
|
||||
child = add_regulator(TWL6025_REG_LDOLN, pdata->ldoln,
|
||||
features);
|
||||
if (IS_ERR(child))
|
||||
return PTR_ERR(child);
|
||||
|
||||
child = add_regulator(TWL6030_REG_VDAC, pdata->vdac);
|
||||
child = add_regulator(TWL6025_REG_LDO2, pdata->ldo2,
|
||||
features);
|
||||
if (IS_ERR(child))
|
||||
return PTR_ERR(child);
|
||||
|
||||
child = add_regulator(TWL6030_REG_VAUX1_6030, pdata->vaux1);
|
||||
child = add_regulator(TWL6025_REG_LDO4, pdata->ldo4,
|
||||
features);
|
||||
if (IS_ERR(child))
|
||||
return PTR_ERR(child);
|
||||
|
||||
child = add_regulator(TWL6030_REG_VAUX2_6030, pdata->vaux2);
|
||||
child = add_regulator(TWL6025_REG_LDO3, pdata->ldo3,
|
||||
features);
|
||||
if (IS_ERR(child))
|
||||
return PTR_ERR(child);
|
||||
|
||||
child = add_regulator(TWL6030_REG_VAUX3_6030, pdata->vaux3);
|
||||
child = add_regulator(TWL6025_REG_SMPS3, pdata->smps3,
|
||||
features);
|
||||
if (IS_ERR(child))
|
||||
return PTR_ERR(child);
|
||||
|
||||
child = add_regulator(TWL6030_REG_CLK32KG, pdata->clk32kg);
|
||||
child = add_regulator(TWL6025_REG_SMPS4, pdata->smps4,
|
||||
features);
|
||||
if (IS_ERR(child))
|
||||
return PTR_ERR(child);
|
||||
|
||||
child = add_regulator(TWL6025_REG_VIO, pdata->vio6025,
|
||||
features);
|
||||
if (IS_ERR(child))
|
||||
return PTR_ERR(child);
|
||||
|
||||
}
|
||||
|
||||
if (twl_has_bci() && pdata->bci &&
|
||||
@ -1014,6 +1184,7 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
||||
unsigned i;
|
||||
struct twl4030_platform_data *pdata = client->dev.platform_data;
|
||||
u8 temp;
|
||||
int ret = 0;
|
||||
|
||||
if (!pdata) {
|
||||
dev_dbg(&client->dev, "no platform data?\n");
|
||||
@ -1060,6 +1231,12 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
||||
/* setup clock framework */
|
||||
clocks_init(&client->dev, pdata->clock);
|
||||
|
||||
/* read TWL IDCODE Register */
|
||||
if (twl_id == TWL4030_CLASS_ID) {
|
||||
ret = twl_read_idcode_register();
|
||||
WARN(ret < 0, "Error: reading twl_idcode register value\n");
|
||||
}
|
||||
|
||||
/* load power event scripts */
|
||||
if (twl_has_power() && pdata->power)
|
||||
twl4030_power_init(pdata->power);
|
||||
@ -1108,6 +1285,7 @@ static const struct i2c_device_id twl_ids[] = {
|
||||
{ "tps65930", TPS_SUBSET }, /* fewer LDOs and DACs; no charger */
|
||||
{ "tps65920", TPS_SUBSET }, /* fewer LDOs; no codec or charger */
|
||||
{ "twl6030", TWL6030_CLASS }, /* "Phoenix power chip" */
|
||||
{ "twl6025", TWL6030_CLASS | TWL6025_SUBCLASS }, /* "Phoenix lite" */
|
||||
{ /* end of list */ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, twl_ids);
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* MFD driver for twl4030 codec submodule
|
||||
*
|
||||
* Author: Peter Ujfalusi <peter.ujfalusi@nokia.com>
|
||||
* Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
|
||||
*
|
||||
* Copyright: (C) 2009 Nokia Corporation
|
||||
*
|
||||
@ -208,13 +208,15 @@ static int __devinit twl4030_codec_probe(struct platform_device *pdev)
|
||||
if (pdata->audio) {
|
||||
cell = &codec->cells[childs];
|
||||
cell->name = "twl4030-codec";
|
||||
cell->mfd_data = pdata->audio;
|
||||
cell->platform_data = pdata->audio;
|
||||
cell->pdata_size = sizeof(*pdata->audio);
|
||||
childs++;
|
||||
}
|
||||
if (pdata->vibra) {
|
||||
cell = &codec->cells[childs];
|
||||
cell->name = "twl4030-vibra";
|
||||
cell->mfd_data = pdata->vibra;
|
||||
cell->platform_data = pdata->vibra;
|
||||
cell->pdata_size = sizeof(*pdata->vibra);
|
||||
childs++;
|
||||
}
|
||||
|
||||
@ -270,6 +272,6 @@ static void __devexit twl4030_codec_exit(void)
|
||||
}
|
||||
module_exit(twl4030_codec_exit);
|
||||
|
||||
MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@nokia.com>");
|
||||
MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
|
@ -120,7 +120,7 @@ static u8 res_config_addrs[] = {
|
||||
[RES_HFCLKOUT] = 0x8b,
|
||||
[RES_32KCLKOUT] = 0x8e,
|
||||
[RES_RESET] = 0x91,
|
||||
[RES_Main_Ref] = 0x94,
|
||||
[RES_MAIN_REF] = 0x94,
|
||||
};
|
||||
|
||||
static int __init twl4030_write_script_byte(u8 address, u8 byte)
|
||||
@ -448,7 +448,7 @@ static int __init load_twl4030_script(struct twl4030_script *tscript,
|
||||
goto out;
|
||||
}
|
||||
if (tscript->flags & TWL4030_SLEEP_SCRIPT) {
|
||||
if (order)
|
||||
if (!order)
|
||||
pr_warning("TWL4030: Bad order of scripts (sleep "\
|
||||
"script before wakeup) Leads to boot"\
|
||||
"failure on some boards\n");
|
||||
@ -485,9 +485,9 @@ int twl4030_remove_script(u8 flags)
|
||||
return err;
|
||||
}
|
||||
if (flags & TWL4030_WAKEUP12_SCRIPT) {
|
||||
if (err)
|
||||
err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, END_OF_SCRIPT,
|
||||
R_SEQ_ADD_S2A12);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
if (flags & TWL4030_WAKEUP3_SCRIPT) {
|
||||
|
@ -76,8 +76,8 @@ static int twl6030_interrupt_mapping[24] = {
|
||||
USBOTG_INTR_OFFSET, /* Bit 18 ID */
|
||||
USB_PRES_INTR_OFFSET, /* Bit 19 VBUS */
|
||||
CHARGER_INTR_OFFSET, /* Bit 20 CHRG_CTRL */
|
||||
CHARGER_INTR_OFFSET, /* Bit 21 EXT_CHRG */
|
||||
CHARGER_INTR_OFFSET, /* Bit 22 INT_CHRG */
|
||||
CHARGERFAULT_INTR_OFFSET, /* Bit 21 EXT_CHRG */
|
||||
CHARGERFAULT_INTR_OFFSET, /* Bit 22 INT_CHRG */
|
||||
RSV_INTR_OFFSET, /* Bit 23 Reserved */
|
||||
};
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
@ -153,7 +153,6 @@ out:
|
||||
*/
|
||||
static int wl1273_fm_set_volume(struct wl1273_core *core, unsigned int volume)
|
||||
{
|
||||
u16 val;
|
||||
int r;
|
||||
|
||||
if (volume > WL1273_MAX_VOLUME)
|
||||
@ -217,7 +216,8 @@ static int __devinit wl1273_core_probe(struct i2c_client *client,
|
||||
|
||||
cell = &core->cells[children];
|
||||
cell->name = "wl1273_fm_radio";
|
||||
cell->mfd_data = &core;
|
||||
cell->platform_data = &core;
|
||||
cell->pdata_size = sizeof(core);
|
||||
children++;
|
||||
|
||||
core->read = wl1273_fm_read_reg;
|
||||
@ -231,7 +231,8 @@ static int __devinit wl1273_core_probe(struct i2c_client *client,
|
||||
|
||||
dev_dbg(&client->dev, "%s: Have codec.\n", __func__);
|
||||
cell->name = "wl1273-codec";
|
||||
cell->mfd_data = &core;
|
||||
cell->platform_data = &core;
|
||||
cell->pdata_size = sizeof(core);
|
||||
children++;
|
||||
}
|
||||
|
||||
|
@ -1442,7 +1442,7 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
|
||||
struct wm831x_pdata *pdata = wm831x->dev->platform_data;
|
||||
int rev;
|
||||
enum wm831x_parent parent;
|
||||
int ret;
|
||||
int ret, i;
|
||||
|
||||
mutex_init(&wm831x->io_lock);
|
||||
mutex_init(&wm831x->key_lock);
|
||||
@ -1581,6 +1581,17 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
|
||||
}
|
||||
}
|
||||
|
||||
if (pdata) {
|
||||
for (i = 0; i < ARRAY_SIZE(pdata->gpio_defaults); i++) {
|
||||
if (!pdata->gpio_defaults[i])
|
||||
continue;
|
||||
|
||||
wm831x_reg_write(wm831x,
|
||||
WM831X_GPIO1_CONTROL + i,
|
||||
pdata->gpio_defaults[i] & 0xffff);
|
||||
}
|
||||
}
|
||||
|
||||
ret = wm831x_irq_init(wm831x, irq);
|
||||
if (ret != 0)
|
||||
goto err;
|
||||
|
@ -515,12 +515,6 @@ int wm831x_irq_init(struct wm831x *wm831x, int irq)
|
||||
0xffff);
|
||||
}
|
||||
|
||||
if (!irq) {
|
||||
dev_warn(wm831x->dev,
|
||||
"No interrupt specified - functionality limited\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!pdata || !pdata->irq_base) {
|
||||
dev_err(wm831x->dev,
|
||||
"No interrupt base specified, no interrupts\n");
|
||||
@ -567,15 +561,22 @@ int wm831x_irq_init(struct wm831x *wm831x, int irq)
|
||||
#endif
|
||||
}
|
||||
|
||||
ret = request_threaded_irq(irq, NULL, wm831x_irq_thread,
|
||||
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
|
||||
"wm831x", wm831x);
|
||||
if (ret != 0) {
|
||||
dev_err(wm831x->dev, "Failed to request IRQ %d: %d\n",
|
||||
irq, ret);
|
||||
return ret;
|
||||
if (irq) {
|
||||
ret = request_threaded_irq(irq, NULL, wm831x_irq_thread,
|
||||
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
|
||||
"wm831x", wm831x);
|
||||
if (ret != 0) {
|
||||
dev_err(wm831x->dev, "Failed to request IRQ %d: %d\n",
|
||||
irq, ret);
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
dev_warn(wm831x->dev,
|
||||
"No interrupt specified - functionality limited\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Enable top level interrupts, we mask at secondary level */
|
||||
wm831x_reg_write(wm831x, WM831X_SYSTEM_INTERRUPTS_MASK, 0);
|
||||
|
||||
|
@ -245,7 +245,8 @@ static int wm8400_register_codec(struct wm8400 *wm8400)
|
||||
{
|
||||
struct mfd_cell cell = {
|
||||
.name = "wm8400-codec",
|
||||
.mfd_data = wm8400,
|
||||
.platform_data = wm8400,
|
||||
.pdata_size = sizeof(*wm8400),
|
||||
};
|
||||
|
||||
return mfd_add_devices(wm8400->dev, -1, &cell, 1, NULL, 0);
|
||||
|
@ -69,7 +69,7 @@ static int __devinit tmio_mmc_probe(struct platform_device *pdev)
|
||||
if (pdev->num_resources != 2)
|
||||
goto out;
|
||||
|
||||
pdata = mfd_get_data(pdev);
|
||||
pdata = pdev->dev.platform_data;
|
||||
if (!pdata || !pdata->hclk)
|
||||
goto out;
|
||||
|
||||
|
@ -372,7 +372,7 @@ static void tmio_hw_stop(struct platform_device *dev, struct tmio_nand *tmio)
|
||||
|
||||
static int tmio_probe(struct platform_device *dev)
|
||||
{
|
||||
struct tmio_nand_data *data = mfd_get_data(dev);
|
||||
struct tmio_nand_data *data = dev->dev.platform_data;
|
||||
struct resource *fcr = platform_get_resource(dev,
|
||||
IORESOURCE_MEM, 0);
|
||||
struct resource *ccr = platform_get_resource(dev,
|
||||
|
@ -15,7 +15,6 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mfd/core.h>
|
||||
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/can.h>
|
||||
@ -1644,7 +1643,7 @@ static int __devinit ican3_probe(struct platform_device *pdev)
|
||||
struct device *dev;
|
||||
int ret;
|
||||
|
||||
pdata = mfd_get_data(pdev);
|
||||
pdata = pdev->dev.platform_data;
|
||||
if (!pdata)
|
||||
return -ENXIO;
|
||||
|
||||
|
@ -26,7 +26,6 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/ethtool.h>
|
||||
@ -1146,7 +1145,7 @@ static int __devinit ks8842_probe(struct platform_device *pdev)
|
||||
struct resource *iomem;
|
||||
struct net_device *netdev;
|
||||
struct ks8842_adapter *adapter;
|
||||
struct ks8842_platform_data *pdata = mfd_get_data(pdev);
|
||||
struct ks8842_platform_data *pdata = pdev->dev.platform_data;
|
||||
u16 id;
|
||||
unsigned i;
|
||||
|
||||
|
@ -425,16 +425,11 @@ static __devexit int max8925_deinit_charger(struct max8925_power_info *info)
|
||||
static __devinit int max8925_power_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);
|
||||
struct max8925_platform_data *max8925_pdata;
|
||||
struct max8925_power_pdata *pdata = NULL;
|
||||
struct max8925_power_info *info;
|
||||
int ret;
|
||||
|
||||
if (pdev->dev.parent->platform_data) {
|
||||
max8925_pdata = pdev->dev.parent->platform_data;
|
||||
pdata = max8925_pdata->power;
|
||||
}
|
||||
|
||||
pdata = pdev->dev.platform_data;
|
||||
if (!pdata) {
|
||||
dev_err(&pdev->dev, "platform data isn't assigned to "
|
||||
"power supply\n");
|
||||
@ -447,6 +442,7 @@ static __devinit int max8925_power_probe(struct platform_device *pdev)
|
||||
info->chip = chip;
|
||||
info->gpm = chip->i2c;
|
||||
info->adc = chip->adc;
|
||||
platform_set_drvdata(pdev, info);
|
||||
|
||||
info->ac.name = "max8925-ac";
|
||||
info->ac.type = POWER_SUPPLY_TYPE_MAINS;
|
||||
@ -482,8 +478,6 @@ static __devinit int max8925_power_probe(struct platform_device *pdev)
|
||||
info->topoff_threshold = pdata->topoff_threshold;
|
||||
info->fast_charge = pdata->fast_charge;
|
||||
info->set_charger = pdata->set_charger;
|
||||
dev_set_drvdata(&pdev->dev, info);
|
||||
platform_set_drvdata(pdev, info);
|
||||
|
||||
max8925_init_charger(chip, info);
|
||||
return 0;
|
||||
|
@ -15,7 +15,6 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regulator/driver.h>
|
||||
#include <linux/regulator/machine.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/88pm860x.h>
|
||||
|
||||
struct pm8607_regulator_info {
|
||||
@ -399,36 +398,33 @@ static int __devinit pm8607_regulator_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
|
||||
struct pm8607_regulator_info *info = NULL;
|
||||
struct regulator_init_data *pdata;
|
||||
struct mfd_cell *cell;
|
||||
struct regulator_init_data *pdata = pdev->dev.platform_data;
|
||||
struct resource *res;
|
||||
int i;
|
||||
|
||||
cell = pdev->dev.platform_data;
|
||||
if (cell == NULL)
|
||||
return -ENODEV;
|
||||
pdata = cell->mfd_data;
|
||||
if (pdata == NULL)
|
||||
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
|
||||
if (res == NULL) {
|
||||
dev_err(&pdev->dev, "No I/O resource!\n");
|
||||
return -EINVAL;
|
||||
|
||||
}
|
||||
for (i = 0; i < ARRAY_SIZE(pm8607_regulator_info); i++) {
|
||||
info = &pm8607_regulator_info[i];
|
||||
if (!strcmp(info->desc.name, pdata->constraints.name))
|
||||
if (info->desc.id == res->start)
|
||||
break;
|
||||
}
|
||||
if (i > ARRAY_SIZE(pm8607_regulator_info)) {
|
||||
dev_err(&pdev->dev, "Failed to find regulator %s\n",
|
||||
pdata->constraints.name);
|
||||
if ((i < 0) || (i > PM8607_ID_RG_MAX)) {
|
||||
dev_err(&pdev->dev, "Failed to find regulator %llu\n",
|
||||
(unsigned long long)res->start);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
info->i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion;
|
||||
info->chip = chip;
|
||||
|
||||
/* check DVC ramp slope double */
|
||||
if (!strcmp(info->desc.name, "BUCK3"))
|
||||
if (info->chip->buck3_double)
|
||||
info->slope_double = 1;
|
||||
if ((i == PM8607_ID_BUCK3) && info->chip->buck3_double)
|
||||
info->slope_double = 1;
|
||||
|
||||
/* replace driver_data with info */
|
||||
info->regulator = regulator_register(&info->desc, &pdev->dev,
|
||||
pdata, info);
|
||||
if (IS_ERR(info->regulator)) {
|
||||
|
@ -17,7 +17,6 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regulator/driver.h>
|
||||
#include <linux/mfd/abx500.h>
|
||||
#include <linux/mfd/core.h>
|
||||
|
||||
/* LDO registers and some handy masking definitions for AB3100 */
|
||||
#define AB3100_LDO_A 0x40
|
||||
@ -582,7 +581,7 @@ ab3100_regulator_desc[AB3100_NUM_REGULATORS] = {
|
||||
|
||||
static int __devinit ab3100_regulators_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct ab3100_platform_data *plfdata = mfd_get_data(pdev);
|
||||
struct ab3100_platform_data *plfdata = pdev->dev.platform_data;
|
||||
int err = 0;
|
||||
u8 data;
|
||||
int i;
|
||||
|
@ -13,7 +13,6 @@
|
||||
#include <linux/err.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/db8500-prcmu.h>
|
||||
#include <linux/regulator/driver.h>
|
||||
#include <linux/regulator/machine.h>
|
||||
@ -471,7 +470,8 @@ static struct db8500_regulator_info
|
||||
|
||||
static int __devinit db8500_regulator_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct regulator_init_data *db8500_init_data = mfd_get_data(pdev);
|
||||
struct regulator_init_data *db8500_init_data =
|
||||
dev_get_platdata(&pdev->dev);
|
||||
int i, err;
|
||||
|
||||
/* register all regulators */
|
||||
|
@ -23,6 +23,10 @@
|
||||
#define SD1_DVM_SHIFT 5 /* SDCTL1 bit5 */
|
||||
#define SD1_DVM_EN 6 /* SDV1 bit 6 */
|
||||
|
||||
/* bit definitions in SD & LDO control registers */
|
||||
#define OUT_ENABLE 0x1f /* Power U/D sequence as I2C */
|
||||
#define OUT_DISABLE 0x1e /* Power U/D sequence as I2C */
|
||||
|
||||
struct max8925_regulator_info {
|
||||
struct regulator_desc desc;
|
||||
struct regulator_dev *regulator;
|
||||
@ -93,8 +97,8 @@ static int max8925_enable(struct regulator_dev *rdev)
|
||||
struct max8925_regulator_info *info = rdev_get_drvdata(rdev);
|
||||
|
||||
return max8925_set_bits(info->i2c, info->enable_reg,
|
||||
1 << info->enable_bit,
|
||||
1 << info->enable_bit);
|
||||
OUT_ENABLE << info->enable_bit,
|
||||
OUT_ENABLE << info->enable_bit);
|
||||
}
|
||||
|
||||
static int max8925_disable(struct regulator_dev *rdev)
|
||||
@ -102,7 +106,8 @@ static int max8925_disable(struct regulator_dev *rdev)
|
||||
struct max8925_regulator_info *info = rdev_get_drvdata(rdev);
|
||||
|
||||
return max8925_set_bits(info->i2c, info->enable_reg,
|
||||
1 << info->enable_bit, 0);
|
||||
OUT_ENABLE << info->enable_bit,
|
||||
OUT_DISABLE << info->enable_bit);
|
||||
}
|
||||
|
||||
static int max8925_is_enabled(struct regulator_dev *rdev)
|
||||
|
@ -15,7 +15,6 @@
|
||||
#include <linux/regulator/driver.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/err.h>
|
||||
@ -337,7 +336,8 @@ static int __devinit mc13783_regulator_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct mc13xxx_regulator_priv *priv;
|
||||
struct mc13xxx *mc13783 = dev_get_drvdata(pdev->dev.parent);
|
||||
struct mc13783_regulator_platform_data *pdata = mfd_get_data(pdev);
|
||||
struct mc13783_regulator_platform_data *pdata =
|
||||
dev_get_platdata(&pdev->dev);
|
||||
struct mc13783_regulator_init_data *init_data;
|
||||
int i, ret;
|
||||
|
||||
@ -381,7 +381,8 @@ err:
|
||||
static int __devexit mc13783_regulator_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct mc13xxx_regulator_priv *priv = platform_get_drvdata(pdev);
|
||||
struct mc13783_regulator_platform_data *pdata = mfd_get_data(pdev);
|
||||
struct mc13783_regulator_platform_data *pdata =
|
||||
dev_get_platdata(&pdev->dev);
|
||||
int i;
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
@ -15,7 +15,6 @@
|
||||
#include <linux/regulator/driver.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/err.h>
|
||||
@ -521,7 +520,8 @@ static int __devinit mc13892_regulator_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct mc13xxx_regulator_priv *priv;
|
||||
struct mc13xxx *mc13892 = dev_get_drvdata(pdev->dev.parent);
|
||||
struct mc13xxx_regulator_platform_data *pdata = mfd_get_data(pdev);
|
||||
struct mc13xxx_regulator_platform_data *pdata =
|
||||
dev_get_platdata(&pdev->dev);
|
||||
struct mc13xxx_regulator_init_data *init_data;
|
||||
int i, ret;
|
||||
u32 val;
|
||||
@ -595,7 +595,8 @@ err_free:
|
||||
static int __devexit mc13892_regulator_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct mc13xxx_regulator_priv *priv = platform_get_drvdata(pdev);
|
||||
struct mc13xxx_regulator_platform_data *pdata = mfd_get_data(pdev);
|
||||
struct mc13xxx_regulator_platform_data *pdata =
|
||||
dev_get_platdata(&pdev->dev);
|
||||
int i;
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
@ -137,7 +137,7 @@ static struct regulator_desc tps6105x_regulator_desc = {
|
||||
*/
|
||||
static int __devinit tps6105x_regulator_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct tps6105x *tps6105x = mfd_get_data(pdev);
|
||||
struct tps6105x *tps6105x = dev_get_platdata(&pdev->dev);
|
||||
struct tps6105x_platform_data *pdata = tps6105x->pdata;
|
||||
int ret;
|
||||
|
||||
@ -164,7 +164,7 @@ static int __devinit tps6105x_regulator_probe(struct platform_device *pdev)
|
||||
|
||||
static int __devexit tps6105x_regulator_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct tps6105x *tps6105x = platform_get_drvdata(pdev);
|
||||
struct tps6105x *tps6105x = dev_get_platdata(&pdev->dev);
|
||||
regulator_unregister(tps6105x->regulator);
|
||||
return 0;
|
||||
}
|
||||
|
@ -125,6 +125,16 @@ comment "I2C RTC drivers"
|
||||
|
||||
if I2C
|
||||
|
||||
config RTC_DRV_88PM860X
|
||||
tristate "Marvell 88PM860x"
|
||||
depends on RTC_CLASS && I2C && MFD_88PM860X
|
||||
help
|
||||
If you say yes here you get support for RTC function in Marvell
|
||||
88PM860x chips.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called rtc-88pm860x.
|
||||
|
||||
config RTC_DRV_DS1307
|
||||
tristate "Dallas/Maxim DS1307/37/38/39/40, ST M41T00, EPSON RX-8025"
|
||||
help
|
||||
|
@ -15,6 +15,7 @@ rtc-core-$(CONFIG_RTC_INTF_SYSFS) += rtc-sysfs.o
|
||||
|
||||
# Keep the list ordered.
|
||||
|
||||
obj-$(CONFIG_RTC_DRV_88PM860X) += rtc-88pm860x.o
|
||||
obj-$(CONFIG_RTC_DRV_AB3100) += rtc-ab3100.o
|
||||
obj-$(CONFIG_RTC_DRV_AB8500) += rtc-ab8500.o
|
||||
obj-$(CONFIG_RTC_DRV_AT32AP700X)+= rtc-at32ap700x.o
|
||||
|
427
drivers/rtc/rtc-88pm860x.c
Normal file
427
drivers/rtc/rtc-88pm860x.c
Normal file
@ -0,0 +1,427 @@
|
||||
/*
|
||||
* Real Time Clock driver for Marvell 88PM860x PMIC
|
||||
*
|
||||
* Copyright (c) 2010 Marvell International Ltd.
|
||||
* Author: Haojian Zhuang <haojian.zhuang@marvell.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/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/88pm860x.h>
|
||||
|
||||
#define VRTC_CALIBRATION
|
||||
|
||||
struct pm860x_rtc_info {
|
||||
struct pm860x_chip *chip;
|
||||
struct i2c_client *i2c;
|
||||
struct rtc_device *rtc_dev;
|
||||
struct device *dev;
|
||||
struct delayed_work calib_work;
|
||||
|
||||
int irq;
|
||||
int vrtc;
|
||||
int (*sync)(unsigned int ticks);
|
||||
};
|
||||
|
||||
#define REG_VRTC_MEAS1 0x7D
|
||||
|
||||
#define REG0_ADDR 0xB0
|
||||
#define REG1_ADDR 0xB2
|
||||
#define REG2_ADDR 0xB4
|
||||
#define REG3_ADDR 0xB6
|
||||
|
||||
#define REG0_DATA 0xB1
|
||||
#define REG1_DATA 0xB3
|
||||
#define REG2_DATA 0xB5
|
||||
#define REG3_DATA 0xB7
|
||||
|
||||
/* bit definitions of Measurement Enable Register 2 (0x51) */
|
||||
#define MEAS2_VRTC (1 << 0)
|
||||
|
||||
/* bit definitions of RTC Register 1 (0xA0) */
|
||||
#define ALARM_EN (1 << 3)
|
||||
#define ALARM_WAKEUP (1 << 4)
|
||||
#define ALARM (1 << 5)
|
||||
#define RTC1_USE_XO (1 << 7)
|
||||
|
||||
#define VRTC_CALIB_INTERVAL (HZ * 60 * 10) /* 10 minutes */
|
||||
|
||||
static irqreturn_t rtc_update_handler(int irq, void *data)
|
||||
{
|
||||
struct pm860x_rtc_info *info = (struct pm860x_rtc_info *)data;
|
||||
int mask;
|
||||
|
||||
mask = ALARM | ALARM_WAKEUP;
|
||||
pm860x_set_bits(info->i2c, PM8607_RTC1, mask | ALARM_EN, mask);
|
||||
rtc_update_irq(info->rtc_dev, 1, RTC_AF);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int pm860x_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
|
||||
{
|
||||
struct pm860x_rtc_info *info = dev_get_drvdata(dev);
|
||||
|
||||
if (enabled)
|
||||
pm860x_set_bits(info->i2c, PM8607_RTC1, ALARM, ALARM);
|
||||
else
|
||||
pm860x_set_bits(info->i2c, PM8607_RTC1, ALARM, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate the next alarm time given the requested alarm time mask
|
||||
* and the current time.
|
||||
*/
|
||||
static void rtc_next_alarm_time(struct rtc_time *next, struct rtc_time *now,
|
||||
struct rtc_time *alrm)
|
||||
{
|
||||
unsigned long next_time;
|
||||
unsigned long now_time;
|
||||
|
||||
next->tm_year = now->tm_year;
|
||||
next->tm_mon = now->tm_mon;
|
||||
next->tm_mday = now->tm_mday;
|
||||
next->tm_hour = alrm->tm_hour;
|
||||
next->tm_min = alrm->tm_min;
|
||||
next->tm_sec = alrm->tm_sec;
|
||||
|
||||
rtc_tm_to_time(now, &now_time);
|
||||
rtc_tm_to_time(next, &next_time);
|
||||
|
||||
if (next_time < now_time) {
|
||||
/* Advance one day */
|
||||
next_time += 60 * 60 * 24;
|
||||
rtc_time_to_tm(next_time, next);
|
||||
}
|
||||
}
|
||||
|
||||
static int pm860x_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct pm860x_rtc_info *info = dev_get_drvdata(dev);
|
||||
unsigned char buf[8];
|
||||
unsigned long ticks, base, data;
|
||||
|
||||
pm860x_page_bulk_read(info->i2c, REG0_ADDR, 8, buf);
|
||||
dev_dbg(info->dev, "%x-%x-%x-%x-%x-%x-%x-%x\n", buf[0], buf[1],
|
||||
buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
|
||||
base = (buf[1] << 24) | (buf[3] << 16) | (buf[5] << 8) | buf[7];
|
||||
|
||||
/* load 32-bit read-only counter */
|
||||
pm860x_bulk_read(info->i2c, PM8607_RTC_COUNTER1, 4, buf);
|
||||
data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
|
||||
ticks = base + data;
|
||||
dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n",
|
||||
base, data, ticks);
|
||||
|
||||
rtc_time_to_tm(ticks, tm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pm860x_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct pm860x_rtc_info *info = dev_get_drvdata(dev);
|
||||
unsigned char buf[4];
|
||||
unsigned long ticks, base, data;
|
||||
|
||||
if ((tm->tm_year < 70) || (tm->tm_year > 138)) {
|
||||
dev_dbg(info->dev, "Set time %d out of range. "
|
||||
"Please set time between 1970 to 2038.\n",
|
||||
1900 + tm->tm_year);
|
||||
return -EINVAL;
|
||||
}
|
||||
rtc_tm_to_time(tm, &ticks);
|
||||
|
||||
/* load 32-bit read-only counter */
|
||||
pm860x_bulk_read(info->i2c, PM8607_RTC_COUNTER1, 4, buf);
|
||||
data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
|
||||
base = ticks - data;
|
||||
dev_dbg(info->dev, "set base:0x%lx, RO count:0x%lx, ticks:0x%lx\n",
|
||||
base, data, ticks);
|
||||
|
||||
pm860x_page_reg_write(info->i2c, REG0_DATA, (base >> 24) & 0xFF);
|
||||
pm860x_page_reg_write(info->i2c, REG1_DATA, (base >> 16) & 0xFF);
|
||||
pm860x_page_reg_write(info->i2c, REG2_DATA, (base >> 8) & 0xFF);
|
||||
pm860x_page_reg_write(info->i2c, REG3_DATA, base & 0xFF);
|
||||
|
||||
if (info->sync)
|
||||
info->sync(ticks);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pm860x_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
{
|
||||
struct pm860x_rtc_info *info = dev_get_drvdata(dev);
|
||||
unsigned char buf[8];
|
||||
unsigned long ticks, base, data;
|
||||
int ret;
|
||||
|
||||
pm860x_page_bulk_read(info->i2c, REG0_ADDR, 8, buf);
|
||||
dev_dbg(info->dev, "%x-%x-%x-%x-%x-%x-%x-%x\n", buf[0], buf[1],
|
||||
buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
|
||||
base = (buf[1] << 24) | (buf[3] << 16) | (buf[5] << 8) | buf[7];
|
||||
|
||||
pm860x_bulk_read(info->i2c, PM8607_RTC_EXPIRE1, 4, buf);
|
||||
data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
|
||||
ticks = base + data;
|
||||
dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n",
|
||||
base, data, ticks);
|
||||
|
||||
rtc_time_to_tm(ticks, &alrm->time);
|
||||
ret = pm860x_reg_read(info->i2c, PM8607_RTC1);
|
||||
alrm->enabled = (ret & ALARM_EN) ? 1 : 0;
|
||||
alrm->pending = (ret & (ALARM | ALARM_WAKEUP)) ? 1 : 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pm860x_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
{
|
||||
struct pm860x_rtc_info *info = dev_get_drvdata(dev);
|
||||
struct rtc_time now_tm, alarm_tm;
|
||||
unsigned long ticks, base, data;
|
||||
unsigned char buf[8];
|
||||
int mask;
|
||||
|
||||
pm860x_set_bits(info->i2c, PM8607_RTC1, ALARM_EN, 0);
|
||||
|
||||
pm860x_page_bulk_read(info->i2c, REG0_ADDR, 8, buf);
|
||||
dev_dbg(info->dev, "%x-%x-%x-%x-%x-%x-%x-%x\n", buf[0], buf[1],
|
||||
buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
|
||||
base = (buf[1] << 24) | (buf[3] << 16) | (buf[5] << 8) | buf[7];
|
||||
|
||||
/* load 32-bit read-only counter */
|
||||
pm860x_bulk_read(info->i2c, PM8607_RTC_COUNTER1, 4, buf);
|
||||
data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
|
||||
ticks = base + data;
|
||||
dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n",
|
||||
base, data, ticks);
|
||||
|
||||
rtc_time_to_tm(ticks, &now_tm);
|
||||
rtc_next_alarm_time(&alarm_tm, &now_tm, &alrm->time);
|
||||
/* get new ticks for alarm in 24 hours */
|
||||
rtc_tm_to_time(&alarm_tm, &ticks);
|
||||
data = ticks - base;
|
||||
|
||||
buf[0] = data & 0xff;
|
||||
buf[1] = (data >> 8) & 0xff;
|
||||
buf[2] = (data >> 16) & 0xff;
|
||||
buf[3] = (data >> 24) & 0xff;
|
||||
pm860x_bulk_write(info->i2c, PM8607_RTC_EXPIRE1, 4, buf);
|
||||
if (alrm->enabled) {
|
||||
mask = ALARM | ALARM_WAKEUP | ALARM_EN;
|
||||
pm860x_set_bits(info->i2c, PM8607_RTC1, mask, mask);
|
||||
} else {
|
||||
mask = ALARM | ALARM_WAKEUP | ALARM_EN;
|
||||
pm860x_set_bits(info->i2c, PM8607_RTC1, mask,
|
||||
ALARM | ALARM_WAKEUP);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct rtc_class_ops pm860x_rtc_ops = {
|
||||
.read_time = pm860x_rtc_read_time,
|
||||
.set_time = pm860x_rtc_set_time,
|
||||
.read_alarm = pm860x_rtc_read_alarm,
|
||||
.set_alarm = pm860x_rtc_set_alarm,
|
||||
.alarm_irq_enable = pm860x_rtc_alarm_irq_enable,
|
||||
};
|
||||
|
||||
#ifdef VRTC_CALIBRATION
|
||||
static void calibrate_vrtc_work(struct work_struct *work)
|
||||
{
|
||||
struct pm860x_rtc_info *info = container_of(work,
|
||||
struct pm860x_rtc_info, calib_work.work);
|
||||
unsigned char buf[2];
|
||||
unsigned int sum, data, mean, vrtc_set;
|
||||
int i;
|
||||
|
||||
for (i = 0, sum = 0; i < 16; i++) {
|
||||
msleep(100);
|
||||
pm860x_bulk_read(info->i2c, REG_VRTC_MEAS1, 2, buf);
|
||||
data = (buf[0] << 4) | buf[1];
|
||||
data = (data * 5400) >> 12; /* convert to mv */
|
||||
sum += data;
|
||||
}
|
||||
mean = sum >> 4;
|
||||
vrtc_set = 2700 + (info->vrtc & 0x3) * 200;
|
||||
dev_dbg(info->dev, "mean:%d, vrtc_set:%d\n", mean, vrtc_set);
|
||||
|
||||
sum = pm860x_reg_read(info->i2c, PM8607_RTC_MISC1);
|
||||
data = sum & 0x3;
|
||||
if ((mean + 200) < vrtc_set) {
|
||||
/* try higher voltage */
|
||||
if (++data == 4)
|
||||
goto out;
|
||||
data = (sum & 0xf8) | (data & 0x3);
|
||||
pm860x_reg_write(info->i2c, PM8607_RTC_MISC1, data);
|
||||
} else if ((mean - 200) > vrtc_set) {
|
||||
/* try lower voltage */
|
||||
if (data-- == 0)
|
||||
goto out;
|
||||
data = (sum & 0xf8) | (data & 0x3);
|
||||
pm860x_reg_write(info->i2c, PM8607_RTC_MISC1, data);
|
||||
} else
|
||||
goto out;
|
||||
dev_dbg(info->dev, "set 0x%x to RTC_MISC1\n", data);
|
||||
/* trigger next calibration since VRTC is updated */
|
||||
schedule_delayed_work(&info->calib_work, VRTC_CALIB_INTERVAL);
|
||||
return;
|
||||
out:
|
||||
/* disable measurement */
|
||||
pm860x_set_bits(info->i2c, PM8607_MEAS_EN2, MEAS2_VRTC, 0);
|
||||
dev_dbg(info->dev, "finish VRTC calibration\n");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int __devinit pm860x_rtc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
|
||||
struct pm860x_rtc_pdata *pdata = NULL;
|
||||
struct pm860x_rtc_info *info;
|
||||
struct rtc_time tm;
|
||||
unsigned long ticks = 0;
|
||||
int ret;
|
||||
|
||||
pdata = pdev->dev.platform_data;
|
||||
if (pdata == NULL)
|
||||
dev_warn(&pdev->dev, "No platform data!\n");
|
||||
|
||||
info = kzalloc(sizeof(struct pm860x_rtc_info), GFP_KERNEL);
|
||||
if (!info)
|
||||
return -ENOMEM;
|
||||
info->irq = platform_get_irq(pdev, 0);
|
||||
if (info->irq < 0) {
|
||||
dev_err(&pdev->dev, "No IRQ resource!\n");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
info->chip = chip;
|
||||
info->i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion;
|
||||
info->dev = &pdev->dev;
|
||||
dev_set_drvdata(&pdev->dev, info);
|
||||
|
||||
ret = request_threaded_irq(info->irq, NULL, rtc_update_handler,
|
||||
IRQF_ONESHOT, "rtc", info);
|
||||
if (ret < 0) {
|
||||
dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n",
|
||||
info->irq, ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* set addresses of 32-bit base value for RTC time */
|
||||
pm860x_page_reg_write(info->i2c, REG0_ADDR, REG0_DATA);
|
||||
pm860x_page_reg_write(info->i2c, REG1_ADDR, REG1_DATA);
|
||||
pm860x_page_reg_write(info->i2c, REG2_ADDR, REG2_DATA);
|
||||
pm860x_page_reg_write(info->i2c, REG3_ADDR, REG3_DATA);
|
||||
|
||||
ret = pm860x_rtc_read_time(&pdev->dev, &tm);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Failed to read initial time.\n");
|
||||
goto out_rtc;
|
||||
}
|
||||
if ((tm.tm_year < 70) || (tm.tm_year > 138)) {
|
||||
tm.tm_year = 70;
|
||||
tm.tm_mon = 0;
|
||||
tm.tm_mday = 1;
|
||||
tm.tm_hour = 0;
|
||||
tm.tm_min = 0;
|
||||
tm.tm_sec = 0;
|
||||
ret = pm860x_rtc_set_time(&pdev->dev, &tm);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Failed to set initial time.\n");
|
||||
goto out_rtc;
|
||||
}
|
||||
}
|
||||
rtc_tm_to_time(&tm, &ticks);
|
||||
if (pdata && pdata->sync) {
|
||||
pdata->sync(ticks);
|
||||
info->sync = pdata->sync;
|
||||
}
|
||||
|
||||
info->rtc_dev = rtc_device_register("88pm860x-rtc", &pdev->dev,
|
||||
&pm860x_rtc_ops, THIS_MODULE);
|
||||
ret = PTR_ERR(info->rtc_dev);
|
||||
if (IS_ERR(info->rtc_dev)) {
|
||||
dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret);
|
||||
goto out_rtc;
|
||||
}
|
||||
|
||||
/*
|
||||
* enable internal XO instead of internal 3.25MHz clock since it can
|
||||
* free running in PMIC power-down state.
|
||||
*/
|
||||
pm860x_set_bits(info->i2c, PM8607_RTC1, RTC1_USE_XO, RTC1_USE_XO);
|
||||
|
||||
#ifdef VRTC_CALIBRATION
|
||||
/* <00> -- 2.7V, <01> -- 2.9V, <10> -- 3.1V, <11> -- 3.3V */
|
||||
if (pdata && pdata->vrtc)
|
||||
info->vrtc = pdata->vrtc & 0x3;
|
||||
else
|
||||
info->vrtc = 1;
|
||||
pm860x_set_bits(info->i2c, PM8607_MEAS_EN2, MEAS2_VRTC, MEAS2_VRTC);
|
||||
|
||||
/* calibrate VRTC */
|
||||
INIT_DELAYED_WORK(&info->calib_work, calibrate_vrtc_work);
|
||||
schedule_delayed_work(&info->calib_work, VRTC_CALIB_INTERVAL);
|
||||
#endif /* VRTC_CALIBRATION */
|
||||
return 0;
|
||||
out_rtc:
|
||||
free_irq(info->irq, info);
|
||||
out:
|
||||
kfree(info);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit pm860x_rtc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct pm860x_rtc_info *info = platform_get_drvdata(pdev);
|
||||
|
||||
#ifdef VRTC_CALIBRATION
|
||||
flush_scheduled_work();
|
||||
/* disable measurement */
|
||||
pm860x_set_bits(info->i2c, PM8607_MEAS_EN2, MEAS2_VRTC, 0);
|
||||
#endif /* VRTC_CALIBRATION */
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
rtc_device_unregister(info->rtc_dev);
|
||||
free_irq(info->irq, info);
|
||||
kfree(info);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver pm860x_rtc_driver = {
|
||||
.driver = {
|
||||
.name = "88pm860x-rtc",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = pm860x_rtc_probe,
|
||||
.remove = __devexit_p(pm860x_rtc_remove),
|
||||
};
|
||||
|
||||
static int __init pm860x_rtc_init(void)
|
||||
{
|
||||
return platform_driver_register(&pm860x_rtc_driver);
|
||||
}
|
||||
module_init(pm860x_rtc_init);
|
||||
|
||||
static void __exit pm860x_rtc_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&pm860x_rtc_driver);
|
||||
}
|
||||
module_exit(pm860x_rtc_exit);
|
||||
|
||||
MODULE_DESCRIPTION("Marvell 88PM860x RTC driver");
|
||||
MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
|
||||
MODULE_LICENSE("GPL");
|
@ -18,7 +18,6 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/spi/spi_bitbang.h>
|
||||
#include <linux/spi/xilinx_spi.h>
|
||||
@ -471,7 +470,7 @@ static int __devinit xilinx_spi_probe(struct platform_device *dev)
|
||||
struct spi_master *master;
|
||||
u8 i;
|
||||
|
||||
pdata = mfd_get_data(dev);
|
||||
pdata = dev->dev.platform_data;
|
||||
if (pdata) {
|
||||
num_cs = pdata->num_chipselect;
|
||||
little_endian = pdata->little_endian;
|
||||
|
@ -16,7 +16,6 @@
|
||||
#include <linux/fb.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/backlight.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/88pm860x.h>
|
||||
|
||||
#define MAX_BRIGHTNESS (0xFF)
|
||||
@ -168,7 +167,6 @@ static int pm860x_backlight_probe(struct platform_device *pdev)
|
||||
struct pm860x_backlight_pdata *pdata = NULL;
|
||||
struct pm860x_backlight_data *data;
|
||||
struct backlight_device *bl;
|
||||
struct mfd_cell *cell;
|
||||
struct resource *res;
|
||||
struct backlight_properties props;
|
||||
unsigned char value;
|
||||
@ -181,10 +179,7 @@ static int pm860x_backlight_probe(struct platform_device *pdev)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cell = pdev->dev.platform_data;
|
||||
if (cell == NULL)
|
||||
return -ENODEV;
|
||||
pdata = cell->mfd_data;
|
||||
pdata = pdev->dev.platform_data;
|
||||
if (pdata == NULL) {
|
||||
dev_err(&pdev->dev, "platform data isn't assigned to "
|
||||
"backlight\n");
|
||||
|
@ -250,7 +250,7 @@ static irqreturn_t tmiofb_irq(int irq, void *__info)
|
||||
*/
|
||||
static int tmiofb_hw_stop(struct platform_device *dev)
|
||||
{
|
||||
struct tmio_fb_data *data = mfd_get_data(dev);
|
||||
struct tmio_fb_data *data = dev->dev.platform_data;
|
||||
struct fb_info *info = platform_get_drvdata(dev);
|
||||
struct tmiofb_par *par = info->par;
|
||||
|
||||
@ -311,7 +311,7 @@ static int tmiofb_hw_init(struct platform_device *dev)
|
||||
*/
|
||||
static void tmiofb_hw_mode(struct platform_device *dev)
|
||||
{
|
||||
struct tmio_fb_data *data = mfd_get_data(dev);
|
||||
struct tmio_fb_data *data = dev->dev.platform_data;
|
||||
struct fb_info *info = platform_get_drvdata(dev);
|
||||
struct fb_videomode *mode = info->mode;
|
||||
struct tmiofb_par *par = info->par;
|
||||
@ -557,8 +557,7 @@ static int tmiofb_ioctl(struct fb_info *fbi,
|
||||
static struct fb_videomode *
|
||||
tmiofb_find_mode(struct fb_info *info, struct fb_var_screeninfo *var)
|
||||
{
|
||||
struct tmio_fb_data *data =
|
||||
mfd_get_data(to_platform_device(info->device));
|
||||
struct tmio_fb_data *data = info->device->platform_data;
|
||||
struct fb_videomode *best = NULL;
|
||||
int i;
|
||||
|
||||
@ -578,8 +577,7 @@ static int tmiofb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
|
||||
{
|
||||
|
||||
struct fb_videomode *mode;
|
||||
struct tmio_fb_data *data =
|
||||
mfd_get_data(to_platform_device(info->device));
|
||||
struct tmio_fb_data *data = info->device->platform_data;
|
||||
|
||||
mode = tmiofb_find_mode(info, var);
|
||||
if (!mode || var->bits_per_pixel > 16)
|
||||
@ -680,7 +678,7 @@ static struct fb_ops tmiofb_ops = {
|
||||
static int __devinit tmiofb_probe(struct platform_device *dev)
|
||||
{
|
||||
const struct mfd_cell *cell = mfd_get_cell(dev);
|
||||
struct tmio_fb_data *data = mfd_get_data(dev);
|
||||
struct tmio_fb_data *data = dev->dev.platform_data;
|
||||
struct resource *ccr = platform_get_resource(dev, IORESOURCE_MEM, 1);
|
||||
struct resource *lcr = platform_get_resource(dev, IORESOURCE_MEM, 0);
|
||||
struct resource *vram = platform_get_resource(dev, IORESOURCE_MEM, 2);
|
||||
|
@ -216,7 +216,7 @@ static int ds1wm_find_divisor(int gclk)
|
||||
static void ds1wm_up(struct ds1wm_data *ds1wm_data)
|
||||
{
|
||||
int divisor;
|
||||
struct ds1wm_driver_data *plat = mfd_get_data(ds1wm_data->pdev);
|
||||
struct ds1wm_driver_data *plat = ds1wm_data->pdev->dev.platform_data;
|
||||
|
||||
if (ds1wm_data->cell->enable)
|
||||
ds1wm_data->cell->enable(ds1wm_data->pdev);
|
||||
@ -351,13 +351,21 @@ static int ds1wm_probe(struct platform_device *pdev)
|
||||
ret = -ENOMEM;
|
||||
goto err0;
|
||||
}
|
||||
plat = mfd_get_data(pdev);
|
||||
|
||||
/* calculate bus shift from mem resource */
|
||||
ds1wm_data->bus_shift = resource_size(res) >> 3;
|
||||
|
||||
ds1wm_data->pdev = pdev;
|
||||
ds1wm_data->cell = mfd_get_cell(pdev);
|
||||
if (!ds1wm_data->cell) {
|
||||
ret = -ENODEV;
|
||||
goto err1;
|
||||
}
|
||||
plat = pdev->dev.platform_data;
|
||||
if (!plat) {
|
||||
ret = -ENODEV;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||
if (!res) {
|
||||
|
@ -37,7 +37,6 @@
|
||||
#include <linux/io.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/mfd/rdc321x.h>
|
||||
#include <linux/mfd/core.h>
|
||||
|
||||
#define RDC_WDT_MASK 0x80000000 /* Mask */
|
||||
#define RDC_WDT_EN 0x00800000 /* Enable bit */
|
||||
@ -232,7 +231,7 @@ static int __devinit rdc321x_wdt_probe(struct platform_device *pdev)
|
||||
struct resource *r;
|
||||
struct rdc321x_wdt_pdata *pdata;
|
||||
|
||||
pdata = mfd_get_data(pdev);
|
||||
pdata = pdev->dev.platform_data;
|
||||
if (!pdata) {
|
||||
dev_err(&pdev->dev, "no platform data supplied\n");
|
||||
return -ENODEV;
|
||||
|
@ -91,6 +91,7 @@
|
||||
#define BCI_INTR_OFFSET 2
|
||||
#define MADC_INTR_OFFSET 3
|
||||
#define USB_INTR_OFFSET 4
|
||||
#define CHARGERFAULT_INTR_OFFSET 5
|
||||
#define BCI_PRES_INTR_OFFSET 9
|
||||
#define USB_PRES_INTR_OFFSET 10
|
||||
#define RTC_INTR_OFFSET 11
|
||||
@ -150,7 +151,12 @@
|
||||
#define MMC_PU (0x1 << 3)
|
||||
#define MMC_PD (0x1 << 2)
|
||||
|
||||
|
||||
#define TWL_SIL_TYPE(rev) ((rev) & 0x00FFFFFF)
|
||||
#define TWL_SIL_REV(rev) ((rev) >> 24)
|
||||
#define TWL_SIL_5030 0x09002F
|
||||
#define TWL5030_REV_1_0 0x00
|
||||
#define TWL5030_REV_1_1 0x10
|
||||
#define TWL5030_REV_1_2 0x30
|
||||
|
||||
#define TWL4030_CLASS_ID 0x4030
|
||||
#define TWL6030_CLASS_ID 0x6030
|
||||
@ -165,6 +171,8 @@ static inline int twl_class_is_ ##class(void) \
|
||||
TWL_CLASS_IS(4030, TWL4030_CLASS_ID)
|
||||
TWL_CLASS_IS(6030, TWL6030_CLASS_ID)
|
||||
|
||||
#define TWL6025_SUBCLASS BIT(4) /* TWL6025 has changed registers */
|
||||
|
||||
/*
|
||||
* Read and write single 8-bit registers
|
||||
*/
|
||||
@ -180,6 +188,9 @@ int twl_i2c_read_u8(u8 mod_no, u8 *val, u8 reg);
|
||||
int twl_i2c_write(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes);
|
||||
int twl_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes);
|
||||
|
||||
int twl_get_type(void);
|
||||
int twl_get_version(void);
|
||||
|
||||
int twl6030_interrupt_unmask(u8 bit_mask, u8 offset);
|
||||
int twl6030_interrupt_mask(u8 bit_mask, u8 offset);
|
||||
|
||||
@ -279,7 +290,12 @@ static inline int twl6030_mmc_card_detect(struct device *dev, int slot)
|
||||
*(Use TWL_4030_MODULE_INTBR)
|
||||
*/
|
||||
|
||||
#define REG_IDCODE_7_0 0x00
|
||||
#define REG_IDCODE_15_8 0x01
|
||||
#define REG_IDCODE_16_23 0x02
|
||||
#define REG_IDCODE_31_24 0x03
|
||||
#define REG_GPPUPDCTR1 0x0F
|
||||
#define REG_UNLOCK_TEST_REG 0x12
|
||||
|
||||
/*I2C1 and I2C4(SR) SDA/SCL pull-up control bits */
|
||||
|
||||
@ -288,6 +304,8 @@ static inline int twl6030_mmc_card_detect(struct device *dev, int slot)
|
||||
#define SR_I2C_SCL_CTRL_PU BIT(4)
|
||||
#define SR_I2C_SDA_CTRL_PU BIT(6)
|
||||
|
||||
#define TWL_EEPROM_R_UNLOCK 0x49
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
@ -501,7 +519,7 @@ static inline int twl6030_mmc_card_detect(struct device *dev, int slot)
|
||||
#define RES_32KCLKOUT 26
|
||||
#define RES_RESET 27
|
||||
/* Power Reference */
|
||||
#define RES_Main_Ref 28
|
||||
#define RES_MAIN_REF 28
|
||||
|
||||
#define TOTAL_RESOURCES 28
|
||||
/*
|
||||
@ -593,6 +611,7 @@ enum twl4030_usb_mode {
|
||||
|
||||
struct twl4030_usb_data {
|
||||
enum twl4030_usb_mode usb_mode;
|
||||
unsigned long features;
|
||||
|
||||
int (*phy_init)(struct device *dev);
|
||||
int (*phy_exit)(struct device *dev);
|
||||
@ -699,6 +718,20 @@ struct twl4030_platform_data {
|
||||
struct regulator_init_data *vcxio;
|
||||
struct regulator_init_data *vusb;
|
||||
struct regulator_init_data *clk32kg;
|
||||
/* TWL6025 LDO regulators */
|
||||
struct regulator_init_data *ldo1;
|
||||
struct regulator_init_data *ldo2;
|
||||
struct regulator_init_data *ldo3;
|
||||
struct regulator_init_data *ldo4;
|
||||
struct regulator_init_data *ldo5;
|
||||
struct regulator_init_data *ldo6;
|
||||
struct regulator_init_data *ldo7;
|
||||
struct regulator_init_data *ldoln;
|
||||
struct regulator_init_data *ldousb;
|
||||
/* TWL6025 DCDC regulators */
|
||||
struct regulator_init_data *smps3;
|
||||
struct regulator_init_data *smps4;
|
||||
struct regulator_init_data *vio6025;
|
||||
};
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
@ -780,4 +813,21 @@ static inline int twl4030charger_usb_en(int enable) { return 0; }
|
||||
#define TWL6030_REG_VRTC 47
|
||||
#define TWL6030_REG_CLK32KG 48
|
||||
|
||||
/* LDOs on 6025 have different names */
|
||||
#define TWL6025_REG_LDO2 49
|
||||
#define TWL6025_REG_LDO4 50
|
||||
#define TWL6025_REG_LDO3 51
|
||||
#define TWL6025_REG_LDO5 52
|
||||
#define TWL6025_REG_LDO1 53
|
||||
#define TWL6025_REG_LDO7 54
|
||||
#define TWL6025_REG_LDO6 55
|
||||
#define TWL6025_REG_LDOLN 56
|
||||
#define TWL6025_REG_LDOUSB 57
|
||||
|
||||
/* 6025 DCDC supplies */
|
||||
#define TWL6025_REG_SMPS3 58
|
||||
#define TWL6025_REG_SMPS4 59
|
||||
#define TWL6025_REG_VIO 60
|
||||
|
||||
|
||||
#endif /* End of __TWL4030_H */
|
||||
|
52
include/linux/input/pmic8xxx-keypad.h
Normal file
52
include/linux/input/pmic8xxx-keypad.h
Normal file
@ -0,0 +1,52 @@
|
||||
/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef __PMIC8XXX_KEYPAD_H__
|
||||
#define __PMIC8XXX_KEYPAD_H__
|
||||
|
||||
#include <linux/input/matrix_keypad.h>
|
||||
|
||||
#define PM8XXX_KEYPAD_DEV_NAME "pm8xxx-keypad"
|
||||
|
||||
/**
|
||||
* struct pm8xxx_keypad_platform_data - platform data for keypad
|
||||
* @keymap_data - matrix keymap data
|
||||
* @input_name - input device name
|
||||
* @input_phys_device - input device name
|
||||
* @num_cols - number of columns of keypad
|
||||
* @num_rows - number of row of keypad
|
||||
* @debounce_ms - debounce period in milliseconds
|
||||
* @scan_delay_ms - scan delay in milliseconds
|
||||
* @row_hold_ns - row hold period in nanoseconds
|
||||
* @wakeup - configure keypad as wakeup
|
||||
* @rep - enable or disable key repeat bit
|
||||
*/
|
||||
struct pm8xxx_keypad_platform_data {
|
||||
const struct matrix_keymap_data *keymap_data;
|
||||
|
||||
const char *input_name;
|
||||
const char *input_phys_device;
|
||||
|
||||
unsigned int num_cols;
|
||||
unsigned int num_rows;
|
||||
unsigned int rows_gpio_start;
|
||||
unsigned int cols_gpio_start;
|
||||
|
||||
unsigned int debounce_ms;
|
||||
unsigned int scan_delay_ms;
|
||||
unsigned int row_hold_ns;
|
||||
|
||||
bool wakeup;
|
||||
bool rep;
|
||||
};
|
||||
|
||||
#endif /*__PMIC8XXX_KEYPAD_H__ */
|
31
include/linux/input/pmic8xxx-pwrkey.h
Normal file
31
include/linux/input/pmic8xxx-pwrkey.h
Normal file
@ -0,0 +1,31 @@
|
||||
/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef __PMIC8XXX_PWRKEY_H__
|
||||
#define __PMIC8XXX_PWRKEY_H__
|
||||
|
||||
#define PM8XXX_PWRKEY_DEV_NAME "pm8xxx-pwrkey"
|
||||
|
||||
/**
|
||||
* struct pm8xxx_pwrkey_platform_data - platform data for pwrkey driver
|
||||
* @pull up: power on register control for pull up/down configuration
|
||||
* @kpd_trigger_delay_us: time delay for power key state change interrupt
|
||||
* trigger.
|
||||
* @wakeup: configure power key as wakeup source
|
||||
*/
|
||||
struct pm8xxx_pwrkey_platform_data {
|
||||
bool pull_up;
|
||||
u32 kpd_trigger_delay_us;
|
||||
u32 wakeup;
|
||||
};
|
||||
|
||||
#endif /* __PMIC8XXX_PWRKEY_H__ */
|
@ -330,6 +330,11 @@ struct pm860x_led_pdata {
|
||||
unsigned long flags;
|
||||
};
|
||||
|
||||
struct pm860x_rtc_pdata {
|
||||
int (*sync)(unsigned int ticks);
|
||||
int vrtc;
|
||||
};
|
||||
|
||||
struct pm860x_touch_pdata {
|
||||
int gpadc_prebias;
|
||||
int slot_cycle;
|
||||
@ -349,6 +354,7 @@ struct pm860x_power_pdata {
|
||||
struct pm860x_platform_data {
|
||||
struct pm860x_backlight_pdata *backlight;
|
||||
struct pm860x_led_pdata *led;
|
||||
struct pm860x_rtc_pdata *rtc;
|
||||
struct pm860x_touch_pdata *touch;
|
||||
struct pm860x_power_pdata *power;
|
||||
struct regulator_init_data *regulator;
|
||||
|
@ -34,6 +34,13 @@
|
||||
#define AB5500_2_0 0x21
|
||||
#define AB5500_2_1 0x22
|
||||
|
||||
/* AB8500 CIDs*/
|
||||
#define AB8500_CUTEARLY 0x00
|
||||
#define AB8500_CUT1P0 0x10
|
||||
#define AB8500_CUT1P1 0x11
|
||||
#define AB8500_CUT2P0 0x20
|
||||
#define AB8500_CUT3P0 0x30
|
||||
|
||||
/*
|
||||
* AB3100, EVENTA1, A2 and A3 event register flags
|
||||
* these are catenated into a single 32-bit flag in the code
|
||||
@ -186,6 +193,7 @@ struct abx500_init_settings {
|
||||
struct ab3550_platform_data {
|
||||
struct {unsigned int base; unsigned int count; } irq;
|
||||
void *dev_data[AB3550_NUM_DEVICES];
|
||||
size_t dev_data_sz[AB3550_NUM_DEVICES];
|
||||
struct abx500_init_settings *init_settings;
|
||||
unsigned int init_settings_sz;
|
||||
};
|
||||
|
@ -16,6 +16,13 @@
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
struct led_classdev;
|
||||
struct asic3_led {
|
||||
const char *name;
|
||||
const char *default_trigger;
|
||||
struct led_classdev *cdev;
|
||||
};
|
||||
|
||||
struct asic3_platform_data {
|
||||
u16 *gpio_config;
|
||||
unsigned int gpio_config_num;
|
||||
@ -23,6 +30,8 @@ struct asic3_platform_data {
|
||||
unsigned int irq_base;
|
||||
|
||||
unsigned int gpio_base;
|
||||
|
||||
struct asic3_led *leds;
|
||||
};
|
||||
|
||||
#define ASIC3_NUM_GPIO_BANKS 4
|
||||
@ -111,9 +120,9 @@ struct asic3_platform_data {
|
||||
#define ASIC3_GPIOA11_PWM0 ASIC3_CONFIG_GPIO(11, 1, 1, 0)
|
||||
#define ASIC3_GPIOA12_PWM1 ASIC3_CONFIG_GPIO(12, 1, 1, 0)
|
||||
#define ASIC3_GPIOA15_CONTROL_CX ASIC3_CONFIG_GPIO(15, 1, 1, 0)
|
||||
#define ASIC3_GPIOC0_LED0 ASIC3_CONFIG_GPIO(32, 1, 1, 0)
|
||||
#define ASIC3_GPIOC1_LED1 ASIC3_CONFIG_GPIO(33, 1, 1, 0)
|
||||
#define ASIC3_GPIOC2_LED2 ASIC3_CONFIG_GPIO(34, 1, 1, 0)
|
||||
#define ASIC3_GPIOC0_LED0 ASIC3_CONFIG_GPIO(32, 1, 0, 0)
|
||||
#define ASIC3_GPIOC1_LED1 ASIC3_CONFIG_GPIO(33, 1, 0, 0)
|
||||
#define ASIC3_GPIOC2_LED2 ASIC3_CONFIG_GPIO(34, 1, 0, 0)
|
||||
#define ASIC3_GPIOC3_SPI_RXD ASIC3_CONFIG_GPIO(35, 1, 0, 0)
|
||||
#define ASIC3_GPIOC4_CF_nCD ASIC3_CONFIG_GPIO(36, 1, 0, 0)
|
||||
#define ASIC3_GPIOC4_SPI_TXD ASIC3_CONFIG_GPIO(36, 1, 1, 0)
|
||||
@ -152,6 +161,7 @@ struct asic3_platform_data {
|
||||
#define PWM_TIMEBASE_VALUE(x) ((x)&0xf) /* Low 4 bits sets time base */
|
||||
#define PWM_TIMEBASE_ENABLE (1 << 4) /* Enable clock */
|
||||
|
||||
#define ASIC3_NUM_LEDS 3
|
||||
#define ASIC3_LED_0_Base 0x0700
|
||||
#define ASIC3_LED_1_Base 0x0800
|
||||
#define ASIC3_LED_2_Base 0x0900
|
||||
@ -287,10 +297,17 @@ struct asic3_platform_data {
|
||||
*
|
||||
*****************************************************************************/
|
||||
#define ASIC3_SD_CONFIG_BASE 0x0400 /* Assumes 32 bit addressing */
|
||||
#define ASIC3_SD_CONFIG_SIZE 0x0200 /* Assumes 32 bit addressing */
|
||||
#define ASIC3_SD_CTRL_BASE 0x1000
|
||||
#define ASIC3_SDIO_CTRL_BASE 0x1200
|
||||
|
||||
#define ASIC3_MAP_SIZE_32BIT 0x2000
|
||||
#define ASIC3_MAP_SIZE_16BIT 0x1000
|
||||
|
||||
/* Functions needed by leds-asic3 */
|
||||
|
||||
struct asic3;
|
||||
extern void asic3_write_register(struct asic3 *asic, unsigned int reg, u32 val);
|
||||
extern u32 asic3_read_register(struct asic3 *asic, unsigned int reg);
|
||||
|
||||
#endif /* __ASIC3_H__ */
|
||||
|
@ -33,8 +33,9 @@ struct mfd_cell {
|
||||
int (*suspend)(struct platform_device *dev);
|
||||
int (*resume)(struct platform_device *dev);
|
||||
|
||||
/* mfd_data can be used to pass data to client drivers */
|
||||
void *mfd_data;
|
||||
/* platform data passed to the sub devices drivers */
|
||||
void *platform_data;
|
||||
size_t pdata_size;
|
||||
|
||||
/*
|
||||
* These resources can be specified relative to the parent device.
|
||||
@ -89,24 +90,6 @@ static inline const struct mfd_cell *mfd_get_cell(struct platform_device *pdev)
|
||||
return pdev->mfd_cell;
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a platform device that's been created by mfd_add_devices(), fetch
|
||||
* the .mfd_data entry from the mfd_cell that created it.
|
||||
* Otherwise just return the platform_data pointer.
|
||||
* This maintains compatibility with platform drivers whose devices aren't
|
||||
* created by the mfd layer, and expect platform_data to contain what would've
|
||||
* otherwise been in mfd_data.
|
||||
*/
|
||||
static inline void *mfd_get_data(struct platform_device *pdev)
|
||||
{
|
||||
const struct mfd_cell *cell = mfd_get_cell(pdev);
|
||||
|
||||
if (cell)
|
||||
return cell->mfd_data;
|
||||
else
|
||||
return pdev->dev.platform_data;
|
||||
}
|
||||
|
||||
extern int mfd_add_devices(struct device *parent, int id,
|
||||
struct mfd_cell *cells, int n_devs,
|
||||
struct resource *mem_base,
|
||||
|
81
include/linux/mfd/pm8xxx/core.h
Normal file
81
include/linux/mfd/pm8xxx/core.h
Normal file
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
/*
|
||||
* Qualcomm PMIC 8xxx driver header file
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __MFD_PM8XXX_CORE_H
|
||||
#define __MFD_PM8XXX_CORE_H
|
||||
|
||||
#include <linux/mfd/core.h>
|
||||
|
||||
struct pm8xxx_drvdata {
|
||||
int (*pmic_readb) (const struct device *dev, u16 addr, u8 *val);
|
||||
int (*pmic_writeb) (const struct device *dev, u16 addr, u8 val);
|
||||
int (*pmic_read_buf) (const struct device *dev, u16 addr, u8 *buf,
|
||||
int n);
|
||||
int (*pmic_write_buf) (const struct device *dev, u16 addr, u8 *buf,
|
||||
int n);
|
||||
int (*pmic_read_irq_stat) (const struct device *dev, int irq);
|
||||
void *pm_chip_data;
|
||||
};
|
||||
|
||||
static inline int pm8xxx_readb(const struct device *dev, u16 addr, u8 *val)
|
||||
{
|
||||
struct pm8xxx_drvdata *dd = dev_get_drvdata(dev);
|
||||
|
||||
if (!dd)
|
||||
return -EINVAL;
|
||||
return dd->pmic_readb(dev, addr, val);
|
||||
}
|
||||
|
||||
static inline int pm8xxx_writeb(const struct device *dev, u16 addr, u8 val)
|
||||
{
|
||||
struct pm8xxx_drvdata *dd = dev_get_drvdata(dev);
|
||||
|
||||
if (!dd)
|
||||
return -EINVAL;
|
||||
return dd->pmic_writeb(dev, addr, val);
|
||||
}
|
||||
|
||||
static inline int pm8xxx_read_buf(const struct device *dev, u16 addr, u8 *buf,
|
||||
int n)
|
||||
{
|
||||
struct pm8xxx_drvdata *dd = dev_get_drvdata(dev);
|
||||
|
||||
if (!dd)
|
||||
return -EINVAL;
|
||||
return dd->pmic_read_buf(dev, addr, buf, n);
|
||||
}
|
||||
|
||||
static inline int pm8xxx_write_buf(const struct device *dev, u16 addr, u8 *buf,
|
||||
int n)
|
||||
{
|
||||
struct pm8xxx_drvdata *dd = dev_get_drvdata(dev);
|
||||
|
||||
if (!dd)
|
||||
return -EINVAL;
|
||||
return dd->pmic_write_buf(dev, addr, buf, n);
|
||||
}
|
||||
|
||||
static inline int pm8xxx_read_irq_stat(const struct device *dev, int irq)
|
||||
{
|
||||
struct pm8xxx_drvdata *dd = dev_get_drvdata(dev);
|
||||
|
||||
if (!dd)
|
||||
return -EINVAL;
|
||||
return dd->pmic_read_irq_stat(dev, irq);
|
||||
}
|
||||
|
||||
#endif
|
59
include/linux/mfd/pm8xxx/irq.h
Normal file
59
include/linux/mfd/pm8xxx/irq.h
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
/*
|
||||
* Qualcomm PMIC irq 8xxx driver header file
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __MFD_PM8XXX_IRQ_H
|
||||
#define __MFD_PM8XXX_IRQ_H
|
||||
|
||||
#include <linux/errno.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
struct pm8xxx_irq_core_data {
|
||||
u32 rev;
|
||||
int nirqs;
|
||||
};
|
||||
|
||||
struct pm8xxx_irq_platform_data {
|
||||
int irq_base;
|
||||
struct pm8xxx_irq_core_data irq_cdata;
|
||||
int devirq;
|
||||
int irq_trigger_flag;
|
||||
};
|
||||
|
||||
struct pm_irq_chip;
|
||||
|
||||
#ifdef CONFIG_MFD_PM8XXX_IRQ
|
||||
int pm8xxx_get_irq_stat(struct pm_irq_chip *chip, int irq);
|
||||
struct pm_irq_chip * __devinit pm8xxx_irq_init(struct device *dev,
|
||||
const struct pm8xxx_irq_platform_data *pdata);
|
||||
int __devexit pm8xxx_irq_exit(struct pm_irq_chip *chip);
|
||||
#else
|
||||
static inline int pm8xxx_get_irq_stat(struct pm_irq_chip *chip, int irq)
|
||||
{
|
||||
return -ENXIO;
|
||||
}
|
||||
static inline struct pm_irq_chip * __devinit pm8xxx_irq_init(
|
||||
const struct device *dev,
|
||||
const struct pm8xxx_irq_platform_data *pdata)
|
||||
{
|
||||
return ERR_PTR(-ENXIO);
|
||||
}
|
||||
static inline int __devexit pm8xxx_irq_exit(struct pm_irq_chip *chip)
|
||||
{
|
||||
return -ENXIO;
|
||||
}
|
||||
#endif /* CONFIG_MFD_PM8XXX_IRQ */
|
||||
#endif /* __MFD_PM8XXX_IRQ_H */
|
31
include/linux/mfd/pm8xxx/pm8921.h
Normal file
31
include/linux/mfd/pm8xxx/pm8921.h
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
/*
|
||||
* Qualcomm PMIC 8921 driver header file
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __MFD_PM8921_H
|
||||
#define __MFD_PM8921_H
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/mfd/pm8xxx/irq.h>
|
||||
|
||||
#define PM8921_NR_IRQS 256
|
||||
|
||||
struct pm8921_platform_data {
|
||||
int irq_base;
|
||||
struct pm8xxx_irq_platform_data *irq_pdata;
|
||||
};
|
||||
|
||||
#endif
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* MFD driver for twl4030 codec submodule
|
||||
*
|
||||
* Author: Peter Ujfalusi <peter.ujfalusi@nokia.com>
|
||||
* Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
|
||||
*
|
||||
* Copyright: (C) 2009 Nokia Corporation
|
||||
*
|
||||
|
@ -301,30 +301,4 @@ int wm831x_device_suspend(struct wm831x *wm831x);
|
||||
int wm831x_irq_init(struct wm831x *wm831x, int irq);
|
||||
void wm831x_irq_exit(struct wm831x *wm831x);
|
||||
|
||||
static inline int __must_check wm831x_request_irq(struct wm831x *wm831x,
|
||||
unsigned int irq,
|
||||
irq_handler_t handler,
|
||||
unsigned long flags,
|
||||
const char *name,
|
||||
void *dev)
|
||||
{
|
||||
return request_threaded_irq(irq, NULL, handler, flags, name, dev);
|
||||
}
|
||||
|
||||
static inline void wm831x_free_irq(struct wm831x *wm831x,
|
||||
unsigned int irq, void *dev)
|
||||
{
|
||||
free_irq(irq, dev);
|
||||
}
|
||||
|
||||
static inline void wm831x_disable_irq(struct wm831x *wm831x, int irq)
|
||||
{
|
||||
disable_irq(irq);
|
||||
}
|
||||
|
||||
static inline void wm831x_enable_irq(struct wm831x *wm831x, int irq)
|
||||
{
|
||||
enable_irq(irq);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -105,6 +105,9 @@ struct wm831x_watchdog_pdata {
|
||||
#define WM831X_MAX_LDO 11
|
||||
#define WM831X_MAX_ISINK 2
|
||||
|
||||
#define WM831X_GPIO_CONFIGURE 0x10000
|
||||
#define WM831X_GPIO_NUM 16
|
||||
|
||||
struct wm831x_pdata {
|
||||
/** Used to distinguish multiple WM831x chips */
|
||||
int wm831x_num;
|
||||
@ -119,6 +122,7 @@ struct wm831x_pdata {
|
||||
|
||||
int irq_base;
|
||||
int gpio_base;
|
||||
int gpio_defaults[WM831X_GPIO_NUM];
|
||||
struct wm831x_backlight_pdata *backlight;
|
||||
struct wm831x_backup_pdata *backup;
|
||||
struct wm831x_battery_pdata *battery;
|
||||
|
@ -153,8 +153,7 @@ static int cq93vc_resume(struct snd_soc_codec *codec)
|
||||
|
||||
static int cq93vc_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct davinci_vc *davinci_vc =
|
||||
mfd_get_data(to_platform_device(codec->dev));
|
||||
struct davinci_vc *davinci_vc = codec->dev->platform_data;
|
||||
|
||||
davinci_vc->cq93vc.codec = codec;
|
||||
codec->control_data = davinci_vc;
|
||||
|
@ -26,7 +26,6 @@
|
||||
#include <linux/pm.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/i2c/twl.h>
|
||||
#include <linux/slab.h>
|
||||
#include <sound/core.h>
|
||||
@ -733,8 +732,7 @@ static int aif_event(struct snd_soc_dapm_widget *w,
|
||||
|
||||
static void headset_ramp(struct snd_soc_codec *codec, int ramp)
|
||||
{
|
||||
struct twl4030_codec_audio_data *pdata =
|
||||
mfd_get_data(to_platform_device(codec->dev));
|
||||
struct twl4030_codec_audio_data *pdata = codec->dev->platform_data;
|
||||
unsigned char hs_gain, hs_pop;
|
||||
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
|
||||
/* Base values for ramp delay calculation: 2^19 - 2^26 */
|
||||
@ -2299,7 +2297,7 @@ static struct snd_soc_codec_driver soc_codec_dev_twl4030 = {
|
||||
|
||||
static int __devinit twl4030_codec_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct twl4030_codec_audio_data *pdata = mfd_get_data(pdev);
|
||||
struct twl4030_codec_audio_data *pdata = pdev->dev.platform_data;
|
||||
|
||||
if (!pdata) {
|
||||
dev_err(&pdev->dev, "platform_data is missing\n");
|
||||
|
@ -441,8 +441,7 @@ EXPORT_SYMBOL_GPL(wl1273_get_format);
|
||||
|
||||
static int wl1273_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct wl1273_core **core =
|
||||
mfd_get_data(to_platform_device(codec->dev));
|
||||
struct wl1273_core **core = codec->dev->platform_data;
|
||||
struct wl1273_priv *wl1273;
|
||||
int r;
|
||||
|
||||
|
@ -1378,7 +1378,7 @@ static void wm8400_probe_deferred(struct work_struct *work)
|
||||
|
||||
static int wm8400_codec_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct wm8400 *wm8400 = mfd_get_data(to_platform_device(codec->dev));
|
||||
struct wm8400 *wm8400 = dev_get_platdata(codec->dev);
|
||||
struct wm8400_priv *priv;
|
||||
int ret;
|
||||
u16 reg;
|
||||
|
@ -205,7 +205,7 @@ static struct snd_soc_dai_driver davinci_vcif_dai = {
|
||||
|
||||
static int davinci_vcif_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct davinci_vc *davinci_vc = mfd_get_data(pdev);
|
||||
struct davinci_vc *davinci_vc = pdev->dev.platform_data;
|
||||
struct davinci_vcif_dev *davinci_vcif_dev;
|
||||
int ret;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user