提交 c269bc00 编写于 作者: L Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/lrg/voltage-2.6

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/lrg/voltage-2.6: (26 commits)
  mfd: Fix warning in WM8350
  mfd: Add placeholders for WM8350 client devices
  da903x: add regulator support for DA9030/DA9034
  mfd: Add WM8350 subdevice registration helper
  regulator: Add WM8350 regulator support
  mfd: Add WM8350 interrupt support
  mfd: Add initialisation callback for WM8350
  mfd: Add GPIO pin configuration support for WM8350
  mfd: Add I2C control support for WM8350
  mfd: Core support for the WM8350 AudioPlus PMIC
  mfd: Add WM8350 watchdog register definitions
  mfd: Add WM8350 RTC register definitions
  mfd: Add WM8350 comparator register definitions
  mfd: Add WM8350 PMU register definitions
  mfd: Add WM8350 PMIC register definitions
  mfd: Add WM8350 GPIO register definitions
  mfd: Add WM8350 audio register definitions
  regulator: Export regulator name via sysfs
  regulator: Add WM8400 regulator support
  mfd: Core support for the WM8400 AudioPlus HiFi CODEC and PMU
  ...
What: /sys/class/regulator/.../state
Date: April 2008
KernelVersion: 2.6.26
Contact: Liam Girdwood <lg@opensource.wolfsonmicro.com>
Contact: Liam Girdwood <lrg@slimlogic.co.uk>
Description:
Each regulator directory will contain a field called
state. This holds the regulator output state.
......@@ -27,7 +27,7 @@ Description:
What: /sys/class/regulator/.../type
Date: April 2008
KernelVersion: 2.6.26
Contact: Liam Girdwood <lg@opensource.wolfsonmicro.com>
Contact: Liam Girdwood <lrg@slimlogic.co.uk>
Description:
Each regulator directory will contain a field called
type. This holds the regulator type.
......@@ -51,7 +51,7 @@ Description:
What: /sys/class/regulator/.../microvolts
Date: April 2008
KernelVersion: 2.6.26
Contact: Liam Girdwood <lg@opensource.wolfsonmicro.com>
Contact: Liam Girdwood <lrg@slimlogic.co.uk>
Description:
Each regulator directory will contain a field called
microvolts. This holds the regulator output voltage setting
......@@ -65,7 +65,7 @@ Description:
What: /sys/class/regulator/.../microamps
Date: April 2008
KernelVersion: 2.6.26
Contact: Liam Girdwood <lg@opensource.wolfsonmicro.com>
Contact: Liam Girdwood <lrg@slimlogic.co.uk>
Description:
Each regulator directory will contain a field called
microamps. This holds the regulator output current limit
......@@ -79,7 +79,7 @@ Description:
What: /sys/class/regulator/.../opmode
Date: April 2008
KernelVersion: 2.6.26
Contact: Liam Girdwood <lg@opensource.wolfsonmicro.com>
Contact: Liam Girdwood <lrg@slimlogic.co.uk>
Description:
Each regulator directory will contain a field called
opmode. This holds the regulator operating mode setting.
......@@ -102,7 +102,7 @@ Description:
What: /sys/class/regulator/.../min_microvolts
Date: April 2008
KernelVersion: 2.6.26
Contact: Liam Girdwood <lg@opensource.wolfsonmicro.com>
Contact: Liam Girdwood <lrg@slimlogic.co.uk>
Description:
Each regulator directory will contain a field called
min_microvolts. This holds the minimum safe working regulator
......@@ -116,7 +116,7 @@ Description:
What: /sys/class/regulator/.../max_microvolts
Date: April 2008
KernelVersion: 2.6.26
Contact: Liam Girdwood <lg@opensource.wolfsonmicro.com>
Contact: Liam Girdwood <lrg@slimlogic.co.uk>
Description:
Each regulator directory will contain a field called
max_microvolts. This holds the maximum safe working regulator
......@@ -130,7 +130,7 @@ Description:
What: /sys/class/regulator/.../min_microamps
Date: April 2008
KernelVersion: 2.6.26
Contact: Liam Girdwood <lg@opensource.wolfsonmicro.com>
Contact: Liam Girdwood <lrg@slimlogic.co.uk>
Description:
Each regulator directory will contain a field called
min_microamps. This holds the minimum safe working regulator
......@@ -145,7 +145,7 @@ Description:
What: /sys/class/regulator/.../max_microamps
Date: April 2008
KernelVersion: 2.6.26
Contact: Liam Girdwood <lg@opensource.wolfsonmicro.com>
Contact: Liam Girdwood <lrg@slimlogic.co.uk>
Description:
Each regulator directory will contain a field called
max_microamps. This holds the maximum safe working regulator
......@@ -157,10 +157,23 @@ Description:
platform code.
What: /sys/class/regulator/.../name
Date: October 2008
KernelVersion: 2.6.28
Contact: Liam Girdwood <lrg@slimlogic.co.uk>
Description:
Each regulator directory will contain a field called
name. This holds a string identifying the regulator for
display purposes.
NOTE: this will be empty if no suitable name is provided
by platform or regulator drivers.
What: /sys/class/regulator/.../num_users
Date: April 2008
KernelVersion: 2.6.26
Contact: Liam Girdwood <lg@opensource.wolfsonmicro.com>
Contact: Liam Girdwood <lrg@slimlogic.co.uk>
Description:
Each regulator directory will contain a field called
num_users. This holds the number of consumer devices that
......@@ -170,7 +183,7 @@ Description:
What: /sys/class/regulator/.../requested_microamps
Date: April 2008
KernelVersion: 2.6.26
Contact: Liam Girdwood <lg@opensource.wolfsonmicro.com>
Contact: Liam Girdwood <lrg@slimlogic.co.uk>
Description:
Each regulator directory will contain a field called
requested_microamps. This holds the total requested load
......@@ -181,7 +194,7 @@ Description:
What: /sys/class/regulator/.../parent
Date: April 2008
KernelVersion: 2.6.26
Contact: Liam Girdwood <lg@opensource.wolfsonmicro.com>
Contact: Liam Girdwood <lrg@slimlogic.co.uk>
Description:
Some regulator directories will contain a link called parent.
This points to the parent or supply regulator if one exists.
......@@ -189,7 +202,7 @@ Description:
What: /sys/class/regulator/.../suspend_mem_microvolts
Date: May 2008
KernelVersion: 2.6.26
Contact: Liam Girdwood <lg@opensource.wolfsonmicro.com>
Contact: Liam Girdwood <lrg@slimlogic.co.uk>
Description:
Each regulator directory will contain a field called
suspend_mem_microvolts. This holds the regulator output
......@@ -203,7 +216,7 @@ Description:
What: /sys/class/regulator/.../suspend_disk_microvolts
Date: May 2008
KernelVersion: 2.6.26
Contact: Liam Girdwood <lg@opensource.wolfsonmicro.com>
Contact: Liam Girdwood <lrg@slimlogic.co.uk>
Description:
Each regulator directory will contain a field called
suspend_disk_microvolts. This holds the regulator output
......@@ -217,7 +230,7 @@ Description:
What: /sys/class/regulator/.../suspend_standby_microvolts
Date: May 2008
KernelVersion: 2.6.26
Contact: Liam Girdwood <lg@opensource.wolfsonmicro.com>
Contact: Liam Girdwood <lrg@slimlogic.co.uk>
Description:
Each regulator directory will contain a field called
suspend_standby_microvolts. This holds the regulator output
......@@ -231,7 +244,7 @@ Description:
What: /sys/class/regulator/.../suspend_mem_mode
Date: May 2008
KernelVersion: 2.6.26
Contact: Liam Girdwood <lg@opensource.wolfsonmicro.com>
Contact: Liam Girdwood <lrg@slimlogic.co.uk>
Description:
Each regulator directory will contain a field called
suspend_mem_mode. This holds the regulator operating mode
......@@ -245,7 +258,7 @@ Description:
What: /sys/class/regulator/.../suspend_disk_mode
Date: May 2008
KernelVersion: 2.6.26
Contact: Liam Girdwood <lg@opensource.wolfsonmicro.com>
Contact: Liam Girdwood <lrg@slimlogic.co.uk>
Description:
Each regulator directory will contain a field called
suspend_disk_mode. This holds the regulator operating mode
......@@ -258,7 +271,7 @@ Description:
What: /sys/class/regulator/.../suspend_standby_mode
Date: May 2008
KernelVersion: 2.6.26
Contact: Liam Girdwood <lg@opensource.wolfsonmicro.com>
Contact: Liam Girdwood <lrg@slimlogic.co.uk>
Description:
Each regulator directory will contain a field called
suspend_standby_mode. This holds the regulator operating mode
......@@ -272,7 +285,7 @@ Description:
What: /sys/class/regulator/.../suspend_mem_state
Date: May 2008
KernelVersion: 2.6.26
Contact: Liam Girdwood <lg@opensource.wolfsonmicro.com>
Contact: Liam Girdwood <lrg@slimlogic.co.uk>
Description:
Each regulator directory will contain a field called
suspend_mem_state. This holds the regulator operating state
......@@ -287,7 +300,7 @@ Description:
What: /sys/class/regulator/.../suspend_disk_state
Date: May 2008
KernelVersion: 2.6.26
Contact: Liam Girdwood <lg@opensource.wolfsonmicro.com>
Contact: Liam Girdwood <lrg@slimlogic.co.uk>
Description:
Each regulator directory will contain a field called
suspend_disk_state. This holds the regulator operating state
......@@ -302,7 +315,7 @@ Description:
What: /sys/class/regulator/.../suspend_standby_state
Date: May 2008
KernelVersion: 2.6.26
Contact: Liam Girdwood <lg@opensource.wolfsonmicro.com>
Contact: Liam Girdwood <lrg@slimlogic.co.uk>
Description:
Each regulator directory will contain a field called
suspend_standby_state. This holds the regulator operating
......
......@@ -2,17 +2,8 @@ Regulator Machine Driver Interface
===================================
The regulator machine driver interface is intended for board/machine specific
initialisation code to configure the regulator subsystem. Typical things that
machine drivers would do are :-
initialisation code to configure the regulator subsystem.
1. Regulator -> Device mapping.
2. Regulator supply configuration.
3. Power Domain constraint setting.
1. Regulator -> device mapping
==============================
Consider the following machine :-
Regulator-1 -+-> Regulator-2 --> [Consumer A @ 1.8 - 2.0V]
......@@ -21,81 +12,82 @@ Consider the following machine :-
The drivers for consumers A & B must be mapped to the correct regulator in
order to control their power supply. This mapping can be achieved in machine
initialisation code by calling :-
initialisation code by creating a struct regulator_consumer_supply for
each regulator.
struct regulator_consumer_supply {
struct device *dev; /* consumer */
const char *supply; /* consumer supply - e.g. "vcc" */
};
int regulator_set_device_supply(const char *regulator, struct device *dev,
const char *supply);
e.g. for the machine above
and is shown with the following code :-
static struct regulator_consumer_supply regulator1_consumers[] = {
{
.dev = &platform_consumerB_device.dev,
.supply = "Vcc",
},};
regulator_set_device_supply("Regulator-1", devB, "Vcc");
regulator_set_device_supply("Regulator-2", devA, "Vcc");
static struct regulator_consumer_supply regulator2_consumers[] = {
{
.dev = &platform_consumerA_device.dev,
.supply = "Vcc",
},};
This maps Regulator-1 to the 'Vcc' supply for Consumer B and maps Regulator-2
to the 'Vcc' supply for Consumer A.
2. Regulator supply configuration.
==================================
Consider the following machine (again) :-
Regulator-1 -+-> Regulator-2 --> [Consumer A @ 1.8 - 2.0V]
|
+-> [Consumer B @ 3.3V]
Constraints can now be registered by defining a struct regulator_init_data
for each regulator power domain. This structure also maps the consumers
to their supply regulator :-
static struct regulator_init_data regulator1_data = {
.constraints = {
.min_uV = 3300000,
.max_uV = 3300000,
.valid_modes_mask = REGULATOR_MODE_NORMAL,
},
.num_consumer_supplies = ARRAY_SIZE(regulator1_consumers),
.consumer_supplies = regulator1_consumers,
};
Regulator-1 supplies power to Regulator-2. This relationship must be registered
with the core so that Regulator-1 is also enabled when Consumer A enables it's
supply (Regulator-2).
This relationship can be register with the core via :-
int regulator_set_supply(const char *regulator, const char *regulator_supply);
In this example we would use the following code :-
regulator_set_supply("Regulator-2", "Regulator-1");
Relationships can be queried by calling :-
const char *regulator_get_supply(const char *regulator);
3. Power Domain constraint setting.
===================================
Each power domain within a system has physical constraints on voltage and
current. This must be defined in software so that the power domain is always
operated within specifications.
Consider the following machine (again) :-
Regulator-1 -+-> Regulator-2 --> [Consumer A @ 1.8 - 2.0V]
|
+-> [Consumer B @ 3.3V]
This gives us two regulators and two power domains:
Domain 1: Regulator-2, Consumer B.
Domain 2: Consumer A.
Constraints can be registered by calling :-
int regulator_set_platform_constraints(const char *regulator,
struct regulation_constraints *constraints);
The example is defined as follows :-
struct regulation_constraints domain_1 = {
.min_uV = 3300000,
.max_uV = 3300000,
.valid_modes_mask = REGULATOR_MODE_NORMAL,
supply (Regulator-2). The supply regulator is set by the supply_regulator_dev
field below:-
static struct regulator_init_data regulator2_data = {
.supply_regulator_dev = &platform_regulator1_device.dev,
.constraints = {
.min_uV = 1800000,
.max_uV = 2000000,
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
.valid_modes_mask = REGULATOR_MODE_NORMAL,
},
.num_consumer_supplies = ARRAY_SIZE(regulator2_consumers),
.consumer_supplies = regulator2_consumers,
};
struct regulation_constraints domain_2 = {
.min_uV = 1800000,
.max_uV = 2000000,
.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
.valid_modes_mask = REGULATOR_MODE_NORMAL,
Finally the regulator devices must be registered in the usual manner.
static struct platform_device regulator_devices[] = {
{
.name = "regulator",
.id = DCDC_1,
.dev = {
.platform_data = &regulator1_data,
},
},
{
.name = "regulator",
.id = DCDC_2,
.dev = {
.platform_data = &regulator2_data,
},
},
};
/* register regulator 1 device */
platform_device_register(&wm8350_regulator_devices[0]);
regulator_set_platform_constraints("Regulator-1", &domain_1);
regulator_set_platform_constraints("Regulator-2", &domain_2);
/* register regulator 2 device */
platform_device_register(&wm8350_regulator_devices[1]);
......@@ -10,11 +10,11 @@ Registration
Drivers can register a regulator by calling :-
struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
void *reg_data);
struct regulator_dev *regulator_register(struct device *dev,
struct regulator_desc *regulator_desc);
This will register the regulators capabilities and operations the regulator
core. The core does not touch reg_data (private to regulator driver).
This will register the regulators capabilities and operations to the regulator
core.
Regulators can be unregistered by calling :-
......
......@@ -4520,10 +4520,11 @@ S: Maintained
VOLTAGE AND CURRENT REGULATOR FRAMEWORK
P: Liam Girdwood
M: lg@opensource.wolfsonmicro.com
M: lrg@slimlogic.co.uk
P: Mark Brown
M: broonie@opensource.wolfsonmicro.com
W: http://opensource.wolfsonmicro.com/node/15
W: http://www.slimlogic.co.uk/?page_id=5
T: git kernel.org/pub/scm/linux/kernel/git/lrg/voltage-2.6.git
S: Supported
......
......@@ -87,6 +87,44 @@ config MFD_TC6393XB
help
Support for Toshiba Mobile IO Controller TC6393XB
config MFD_WM8400
tristate "Support Wolfson Microelectronics WM8400"
help
Support for the Wolfson Microelecronics WM8400 PMIC and audio
CODEC. This driver adds provides common support for accessing
the device, additional drivers must be enabled in order to use
the functionality of the device.
config MFD_WM8350
tristate
config MFD_WM8350_CONFIG_MODE_0
bool
depends on MFD_WM8350
config MFD_WM8350_CONFIG_MODE_1
bool
depends on MFD_WM8350
config MFD_WM8350_CONFIG_MODE_2
bool
depends on MFD_WM8350
config MFD_WM8350_CONFIG_MODE_3
bool
depends on MFD_WM8350
config MFD_WM8350_I2C
tristate "Support Wolfson Microelectronics WM8350 with I2C"
select MFD_WM8350
depends on I2C
help
The WM8350 is an integrated audio and power management
subsystem with watchdog and RTC functionality for embedded
systems. This option enables core support for the WM8350 with
I2C as the control interface. Additional options must be
selected to enable support for the functionality of the chip.
endmenu
menu "Multimedia Capabilities Port drivers"
......
......@@ -12,6 +12,11 @@ obj-$(CONFIG_MFD_T7L66XB) += t7l66xb.o
obj-$(CONFIG_MFD_TC6387XB) += tc6387xb.o
obj-$(CONFIG_MFD_TC6393XB) += tc6393xb.o
obj-$(CONFIG_MFD_WM8400) += wm8400-core.o
wm8350-objs := wm8350-core.o wm8350-regmap.o wm8350-gpio.o
obj-$(CONFIG_MFD_WM8350) += wm8350.o
obj-$(CONFIG_MFD_WM8350_I2C) += wm8350-i2c.o
obj-$(CONFIG_MFD_CORE) += mfd-core.o
obj-$(CONFIG_MCP) += mcp-core.o
......
此差异已折叠。
/*
* wm8350-core.c -- Device access for Wolfson WM8350
*
* Copyright 2007, 2008 Wolfson Microelectronics PLC.
*
* Author: Liam Girdwood
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/mfd/wm8350/core.h>
#include <linux/mfd/wm8350/gpio.h>
#include <linux/mfd/wm8350/pmic.h>
static int gpio_set_dir(struct wm8350 *wm8350, int gpio, int dir)
{
int ret;
wm8350_reg_unlock(wm8350);
if (dir == WM8350_GPIO_DIR_OUT)
ret = wm8350_clear_bits(wm8350,
WM8350_GPIO_CONFIGURATION_I_O,
1 << gpio);
else
ret = wm8350_set_bits(wm8350,
WM8350_GPIO_CONFIGURATION_I_O,
1 << gpio);
wm8350_reg_lock(wm8350);
return ret;
}
static int gpio_set_debounce(struct wm8350 *wm8350, int gpio, int db)
{
if (db == WM8350_GPIO_DEBOUNCE_ON)
return wm8350_set_bits(wm8350, WM8350_GPIO_DEBOUNCE,
1 << gpio);
else
return wm8350_clear_bits(wm8350,
WM8350_GPIO_DEBOUNCE, 1 << gpio);
}
static int gpio_set_func(struct wm8350 *wm8350, int gpio, int func)
{
u16 reg;
wm8350_reg_unlock(wm8350);
switch (gpio) {
case 0:
reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_1)
& ~WM8350_GP0_FN_MASK;
wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_1,
reg | ((func & 0xf) << 0));
break;
case 1:
reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_1)
& ~WM8350_GP1_FN_MASK;
wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_1,
reg | ((func & 0xf) << 4));
break;
case 2:
reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_1)
& ~WM8350_GP2_FN_MASK;
wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_1,
reg | ((func & 0xf) << 8));
break;
case 3:
reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_1)
& ~WM8350_GP3_FN_MASK;
wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_1,
reg | ((func & 0xf) << 12));
break;
case 4:
reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_2)
& ~WM8350_GP4_FN_MASK;
wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_2,
reg | ((func & 0xf) << 0));
break;
case 5:
reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_2)
& ~WM8350_GP5_FN_MASK;
wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_2,
reg | ((func & 0xf) << 4));
break;
case 6:
reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_2)
& ~WM8350_GP6_FN_MASK;
wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_2,
reg | ((func & 0xf) << 8));
break;
case 7:
reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_2)
& ~WM8350_GP7_FN_MASK;
wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_2,
reg | ((func & 0xf) << 12));
break;
case 8:
reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_3)
& ~WM8350_GP8_FN_MASK;
wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_3,
reg | ((func & 0xf) << 0));
break;
case 9:
reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_3)
& ~WM8350_GP9_FN_MASK;
wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_3,
reg | ((func & 0xf) << 4));
break;
case 10:
reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_3)
& ~WM8350_GP10_FN_MASK;
wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_3,
reg | ((func & 0xf) << 8));
break;
case 11:
reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_3)
& ~WM8350_GP11_FN_MASK;
wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_3,
reg | ((func & 0xf) << 12));
break;
case 12:
reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_4)
& ~WM8350_GP12_FN_MASK;
wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_4,
reg | ((func & 0xf) << 0));
break;
default:
wm8350_reg_lock(wm8350);
return -EINVAL;
}
wm8350_reg_lock(wm8350);
return 0;
}
static int gpio_set_pull_up(struct wm8350 *wm8350, int gpio, int up)
{
if (up)
return wm8350_set_bits(wm8350,
WM8350_GPIO_PIN_PULL_UP_CONTROL,
1 << gpio);
else
return wm8350_clear_bits(wm8350,
WM8350_GPIO_PIN_PULL_UP_CONTROL,
1 << gpio);
}
static int gpio_set_pull_down(struct wm8350 *wm8350, int gpio, int down)
{
if (down)
return wm8350_set_bits(wm8350,
WM8350_GPIO_PULL_DOWN_CONTROL,
1 << gpio);
else
return wm8350_clear_bits(wm8350,
WM8350_GPIO_PULL_DOWN_CONTROL,
1 << gpio);
}
static int gpio_set_polarity(struct wm8350 *wm8350, int gpio, int pol)
{
if (pol == WM8350_GPIO_ACTIVE_HIGH)
return wm8350_set_bits(wm8350,
WM8350_GPIO_PIN_POLARITY_TYPE,
1 << gpio);
else
return wm8350_clear_bits(wm8350,
WM8350_GPIO_PIN_POLARITY_TYPE,
1 << gpio);
}
static int gpio_set_invert(struct wm8350 *wm8350, int gpio, int invert)
{
if (invert == WM8350_GPIO_INVERT_ON)
return wm8350_set_bits(wm8350, WM8350_GPIO_INT_MODE, 1 << gpio);
else
return wm8350_clear_bits(wm8350,
WM8350_GPIO_INT_MODE, 1 << gpio);
}
int wm8350_gpio_config(struct wm8350 *wm8350, int gpio, int dir, int func,
int pol, int pull, int invert, int debounce)
{
/* make sure we never pull up and down at the same time */
if (pull == WM8350_GPIO_PULL_NONE) {
if (gpio_set_pull_up(wm8350, gpio, 0))
goto err;
if (gpio_set_pull_down(wm8350, gpio, 0))
goto err;
} else if (pull == WM8350_GPIO_PULL_UP) {
if (gpio_set_pull_down(wm8350, gpio, 0))
goto err;
if (gpio_set_pull_up(wm8350, gpio, 1))
goto err;
} else if (pull == WM8350_GPIO_PULL_DOWN) {
if (gpio_set_pull_up(wm8350, gpio, 0))
goto err;
if (gpio_set_pull_down(wm8350, gpio, 1))
goto err;
}
if (gpio_set_invert(wm8350, gpio, invert))
goto err;
if (gpio_set_polarity(wm8350, gpio, pol))
goto err;
if (gpio_set_debounce(wm8350, gpio, debounce))
goto err;
if (gpio_set_dir(wm8350, gpio, dir))
goto err;
return gpio_set_func(wm8350, gpio, func);
err:
return -EIO;
}
EXPORT_SYMBOL_GPL(wm8350_gpio_config);
/*
* wm8350-i2c.c -- Generic I2C driver for Wolfson WM8350 PMIC
*
* This driver defines and configures the WM8350 for the Freescale i.MX32ADS.
*
* Copyright 2007, 2008 Wolfson Microelectronics PLC.
*
* Author: Liam Girdwood
* linux@wolfsonmicro.com
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <linux/mfd/wm8350/core.h>
static int wm8350_i2c_read_device(struct wm8350 *wm8350, char reg,
int bytes, void *dest)
{
int ret;
ret = i2c_master_send(wm8350->i2c_client, &reg, 1);
if (ret < 0)
return ret;
return i2c_master_recv(wm8350->i2c_client, dest, bytes);
}
static int wm8350_i2c_write_device(struct wm8350 *wm8350, char reg,
int bytes, void *src)
{
/* we add 1 byte for device register */
u8 msg[(WM8350_MAX_REGISTER << 1) + 1];
if (bytes > ((WM8350_MAX_REGISTER << 1) + 1))
return -EINVAL;
msg[0] = reg;
memcpy(&msg[1], src, bytes);
return i2c_master_send(wm8350->i2c_client, msg, bytes + 1);
}
static int wm8350_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct wm8350 *wm8350;
int ret = 0;
wm8350 = kzalloc(sizeof(struct wm8350), GFP_KERNEL);
if (wm8350 == NULL) {
kfree(i2c);
return -ENOMEM;
}
i2c_set_clientdata(i2c, wm8350);
wm8350->dev = &i2c->dev;
wm8350->i2c_client = i2c;
wm8350->read_dev = wm8350_i2c_read_device;
wm8350->write_dev = wm8350_i2c_write_device;
ret = wm8350_device_init(wm8350, i2c->irq, i2c->dev.platform_data);
if (ret < 0)
goto err;
return ret;
err:
kfree(wm8350);
return ret;
}
static int wm8350_i2c_remove(struct i2c_client *i2c)
{
struct wm8350 *wm8350 = i2c_get_clientdata(i2c);
wm8350_device_exit(wm8350);
kfree(wm8350);
return 0;
}
static const struct i2c_device_id wm8350_i2c_id[] = {
{ "wm8350", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, wm8350_i2c_id);
static struct i2c_driver wm8350_i2c_driver = {
.driver = {
.name = "wm8350",
.owner = THIS_MODULE,
},
.probe = wm8350_i2c_probe,
.remove = wm8350_i2c_remove,
.id_table = wm8350_i2c_id,
};
static int __init wm8350_i2c_init(void)
{
return i2c_add_driver(&wm8350_i2c_driver);
}
/* init early so consumer devices can complete system boot */
subsys_initcall(wm8350_i2c_init);
static void __exit wm8350_i2c_exit(void)
{
i2c_del_driver(&wm8350_i2c_driver);
}
module_exit(wm8350_i2c_exit);
MODULE_DESCRIPTION("I2C support for the WM8350 AudioPlus PMIC");
MODULE_LICENSE("GPL");
此差异已折叠。
/*
* Core driver for WM8400.
*
* Copyright 2008 Wolfson Microelectronics PLC.
*
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
*/
#include <linux/bug.h>
#include <linux/i2c.h>
#include <linux/kernel.h>
#include <linux/mfd/wm8400-private.h>
#include <linux/mfd/wm8400-audio.h>
static struct {
u16 readable; /* Mask of readable bits */
u16 writable; /* Mask of writable bits */
u16 vol; /* Mask of volatile bits */
int is_codec; /* Register controlled by codec reset */
u16 default_val; /* Value on reset */
} reg_data[] = {
{ 0xFFFF, 0xFFFF, 0x0000, 0, 0x6172 }, /* R0 */
{ 0x7000, 0x0000, 0x8000, 0, 0x0000 }, /* R1 */
{ 0xFF17, 0xFF17, 0x0000, 0, 0x0000 }, /* R2 */
{ 0xEBF3, 0xEBF3, 0x0000, 1, 0x6000 }, /* R3 */
{ 0x3CF3, 0x3CF3, 0x0000, 1, 0x0000 }, /* R4 */
{ 0xF1F8, 0xF1F8, 0x0000, 1, 0x4050 }, /* R5 */
{ 0xFC1F, 0xFC1F, 0x0000, 1, 0x4000 }, /* R6 */
{ 0xDFDE, 0xDFDE, 0x0000, 1, 0x01C8 }, /* R7 */
{ 0xFCFC, 0xFCFC, 0x0000, 1, 0x0000 }, /* R8 */
{ 0xEFFF, 0xEFFF, 0x0000, 1, 0x0040 }, /* R9 */
{ 0xEFFF, 0xEFFF, 0x0000, 1, 0x0040 }, /* R10 */
{ 0x27F7, 0x27F7, 0x0000, 1, 0x0004 }, /* R11 */
{ 0x01FF, 0x01FF, 0x0000, 1, 0x00C0 }, /* R12 */
{ 0x01FF, 0x01FF, 0x0000, 1, 0x00C0 }, /* R13 */
{ 0x1FEF, 0x1FEF, 0x0000, 1, 0x0000 }, /* R14 */
{ 0x0163, 0x0163, 0x0000, 1, 0x0100 }, /* R15 */
{ 0x01FF, 0x01FF, 0x0000, 1, 0x00C0 }, /* R16 */
{ 0x01FF, 0x01FF, 0x0000, 1, 0x00C0 }, /* R17 */
{ 0x1FFF, 0x0FFF, 0x0000, 1, 0x0000 }, /* R18 */
{ 0xFFFF, 0xFFFF, 0x0000, 1, 0x1000 }, /* R19 */
{ 0xFFFF, 0xFFFF, 0x0000, 1, 0x1010 }, /* R20 */
{ 0xFFFF, 0xFFFF, 0x0000, 1, 0x1010 }, /* R21 */
{ 0x0FDD, 0x0FDD, 0x0000, 1, 0x8000 }, /* R22 */
{ 0x1FFF, 0x1FFF, 0x0000, 1, 0x0800 }, /* R23 */
{ 0x0000, 0x01DF, 0x0000, 1, 0x008B }, /* R24 */
{ 0x0000, 0x01DF, 0x0000, 1, 0x008B }, /* R25 */
{ 0x0000, 0x01DF, 0x0000, 1, 0x008B }, /* R26 */
{ 0x0000, 0x01DF, 0x0000, 1, 0x008B }, /* R27 */
{ 0x0000, 0x01FF, 0x0000, 1, 0x0000 }, /* R28 */
{ 0x0000, 0x01FF, 0x0000, 1, 0x0000 }, /* R29 */
{ 0x0000, 0x0077, 0x0000, 1, 0x0066 }, /* R30 */
{ 0x0000, 0x0033, 0x0000, 1, 0x0022 }, /* R31 */
{ 0x0000, 0x01FF, 0x0000, 1, 0x0079 }, /* R32 */
{ 0x0000, 0x01FF, 0x0000, 1, 0x0079 }, /* R33 */
{ 0x0000, 0x0003, 0x0000, 1, 0x0003 }, /* R34 */
{ 0x0000, 0x01FF, 0x0000, 1, 0x0003 }, /* R35 */
{ 0x0000, 0x0000, 0x0000, 0, 0x0000 }, /* R36 */
{ 0x0000, 0x003F, 0x0000, 1, 0x0100 }, /* R37 */
{ 0x0000, 0x0000, 0x0000, 0, 0x0000 }, /* R38 */
{ 0x0000, 0x000F, 0x0000, 0, 0x0000 }, /* R39 */
{ 0x0000, 0x00FF, 0x0000, 1, 0x0000 }, /* R40 */
{ 0x0000, 0x01B7, 0x0000, 1, 0x0000 }, /* R41 */
{ 0x0000, 0x01B7, 0x0000, 1, 0x0000 }, /* R42 */
{ 0x0000, 0x01FF, 0x0000, 1, 0x0000 }, /* R43 */
{ 0x0000, 0x01FF, 0x0000, 1, 0x0000 }, /* R44 */
{ 0x0000, 0x00FD, 0x0000, 1, 0x0000 }, /* R45 */
{ 0x0000, 0x00FD, 0x0000, 1, 0x0000 }, /* R46 */
{ 0x0000, 0x01FF, 0x0000, 1, 0x0000 }, /* R47 */
{ 0x0000, 0x01FF, 0x0000, 1, 0x0000 }, /* R48 */
{ 0x0000, 0x01FF, 0x0000, 1, 0x0000 }, /* R49 */
{ 0x0000, 0x01FF, 0x0000, 1, 0x0000 }, /* R50 */
{ 0x0000, 0x01B3, 0x0000, 1, 0x0180 }, /* R51 */
{ 0x0000, 0x0077, 0x0000, 1, 0x0000 }, /* R52 */
{ 0x0000, 0x0077, 0x0000, 1, 0x0000 }, /* R53 */
{ 0x0000, 0x00FF, 0x0000, 1, 0x0000 }, /* R54 */
{ 0x0000, 0x0001, 0x0000, 1, 0x0000 }, /* R55 */
{ 0x0000, 0x003F, 0x0000, 1, 0x0000 }, /* R56 */
{ 0x0000, 0x004F, 0x0000, 1, 0x0000 }, /* R57 */
{ 0x0000, 0x00FD, 0x0000, 1, 0x0000 }, /* R58 */
{ 0x0000, 0x0000, 0x0000, 0, 0x0000 }, /* R59 */
{ 0x1FFF, 0x1FFF, 0x0000, 1, 0x0000 }, /* R60 */
{ 0xFFFF, 0xFFFF, 0x0000, 1, 0x0000 }, /* R61 */
{ 0x03FF, 0x03FF, 0x0000, 1, 0x0000 }, /* R62 */
{ 0x007F, 0x007F, 0x0000, 1, 0x0000 }, /* R63 */
{ 0x0000, 0x0000, 0x0000, 0, 0x0000 }, /* R64 */
{ 0xDFFF, 0xDFFF, 0x0000, 0, 0x0000 }, /* R65 */
{ 0xDFFF, 0xDFFF, 0x0000, 0, 0x0000 }, /* R66 */
{ 0xDFFF, 0xDFFF, 0x0000, 0, 0x0000 }, /* R67 */
{ 0xDFFF, 0xDFFF, 0x0000, 0, 0x0000 }, /* R68 */
{ 0x0000, 0x0000, 0x0000, 0, 0x0000 }, /* R69 */
{ 0xFFFF, 0xFFFF, 0x0000, 0, 0x4400 }, /* R70 */
{ 0x23FF, 0x23FF, 0x0000, 0, 0x0000 }, /* R71 */
{ 0xFFFF, 0xFFFF, 0x0000, 0, 0x4400 }, /* R72 */
{ 0x23FF, 0x23FF, 0x0000, 0, 0x0000 }, /* R73 */
{ 0x0000, 0x0000, 0x0000, 0, 0x0000 }, /* R74 */
{ 0x000E, 0x000E, 0x0000, 0, 0x0008 }, /* R75 */
{ 0xE00F, 0xE00F, 0x0000, 0, 0x0000 }, /* R76 */
{ 0x0000, 0x0000, 0x0000, 0, 0x0000 }, /* R77 */
{ 0x03C0, 0x03C0, 0x0000, 0, 0x02C0 }, /* R78 */
{ 0xFFFF, 0x0000, 0xffff, 0, 0x0000 }, /* R79 */
{ 0xFFFF, 0xFFFF, 0x0000, 0, 0x0000 }, /* R80 */
{ 0xFFFF, 0x0000, 0xffff, 0, 0x0000 }, /* R81 */
{ 0x2BFF, 0x0000, 0xffff, 0, 0x0000 }, /* R82 */
{ 0x0000, 0x0000, 0x0000, 0, 0x0000 }, /* R83 */
{ 0x80FF, 0x80FF, 0x0000, 0, 0x00ff }, /* R84 */
};
static int wm8400_read(struct wm8400 *wm8400, u8 reg, int num_regs, u16 *dest)
{
int i, ret = 0;
BUG_ON(reg + num_regs - 1 > ARRAY_SIZE(wm8400->reg_cache));
/* If there are any volatile reads then read back the entire block */
for (i = reg; i < reg + num_regs; i++)
if (reg_data[i].vol) {
ret = wm8400->read_dev(wm8400->io_data, reg,
num_regs, dest);
if (ret != 0)
return ret;
for (i = 0; i < num_regs; i++)
dest[i] = be16_to_cpu(dest[i]);
return 0;
}
/* Otherwise use the cache */
memcpy(dest, &wm8400->reg_cache[reg], num_regs * sizeof(u16));
return 0;
}
static int wm8400_write(struct wm8400 *wm8400, u8 reg, int num_regs,
u16 *src)
{
int ret, i;
BUG_ON(reg + num_regs - 1 > ARRAY_SIZE(wm8400->reg_cache));
for (i = 0; i < num_regs; i++) {
BUG_ON(!reg_data[reg + i].writable);
wm8400->reg_cache[reg + i] = src[i];
src[i] = cpu_to_be16(src[i]);
}
/* Do the actual I/O */
ret = wm8400->write_dev(wm8400->io_data, reg, num_regs, src);
if (ret != 0)
return -EIO;
return 0;
}
/**
* wm8400_reg_read - Single register read
*
* @wm8400: Pointer to wm8400 control structure
* @reg: Register to read
*
* @return Read value
*/
u16 wm8400_reg_read(struct wm8400 *wm8400, u8 reg)
{
u16 val;
mutex_lock(&wm8400->io_lock);
wm8400_read(wm8400, reg, 1, &val);
mutex_unlock(&wm8400->io_lock);
return val;
}
EXPORT_SYMBOL_GPL(wm8400_reg_read);
int wm8400_block_read(struct wm8400 *wm8400, u8 reg, int count, u16 *data)
{
int ret;
mutex_lock(&wm8400->io_lock);
ret = wm8400_read(wm8400, reg, count, data);
mutex_unlock(&wm8400->io_lock);
return ret;
}
EXPORT_SYMBOL_GPL(wm8400_block_read);
/**
* wm8400_set_bits - Bitmask write
*
* @wm8400: Pointer to wm8400 control structure
* @reg: Register to access
* @mask: Mask of bits to change
* @val: Value to set for masked bits
*/
int wm8400_set_bits(struct wm8400 *wm8400, u8 reg, u16 mask, u16 val)
{
u16 tmp;
int ret;
mutex_lock(&wm8400->io_lock);
ret = wm8400_read(wm8400, reg, 1, &tmp);
tmp = (tmp & ~mask) | val;
if (ret == 0)
ret = wm8400_write(wm8400, reg, 1, &tmp);
mutex_unlock(&wm8400->io_lock);
return ret;
}
EXPORT_SYMBOL_GPL(wm8400_set_bits);
/**
* wm8400_reset_codec_reg_cache - Reset cached codec registers to
* their default values.
*/
void wm8400_reset_codec_reg_cache(struct wm8400 *wm8400)
{
int i;
mutex_lock(&wm8400->io_lock);
/* Reset all codec registers to their initial value */
for (i = 0; i < ARRAY_SIZE(wm8400->reg_cache); i++)
if (reg_data[i].is_codec)
wm8400->reg_cache[i] = reg_data[i].default_val;
mutex_unlock(&wm8400->io_lock);
}
EXPORT_SYMBOL_GPL(wm8400_reset_codec_reg_cache);
/*
* wm8400_init - Generic initialisation
*
* The WM8400 can be configured as either an I2C or SPI device. Probe
* functions for each bus set up the accessors then call into this to
* set up the device itself.
*/
static int wm8400_init(struct wm8400 *wm8400,
struct wm8400_platform_data *pdata)
{
u16 reg;
int ret, i;
mutex_init(&wm8400->io_lock);
wm8400->dev->driver_data = wm8400;
/* Check that this is actually a WM8400 */
ret = wm8400->read_dev(wm8400->io_data, WM8400_RESET_ID, 1, &reg);
if (ret != 0) {
dev_err(wm8400->dev, "Chip ID register read failed\n");
return -EIO;
}
if (be16_to_cpu(reg) != reg_data[WM8400_RESET_ID].default_val) {
dev_err(wm8400->dev, "Device is not a WM8400, ID is %x\n",
be16_to_cpu(reg));
return -ENODEV;
}
/* We don't know what state the hardware is in and since this
* is a PMIC we can't reset it safely so initialise the register
* cache from the hardware.
*/
ret = wm8400->read_dev(wm8400->io_data, 0,
ARRAY_SIZE(wm8400->reg_cache),
wm8400->reg_cache);
if (ret != 0) {
dev_err(wm8400->dev, "Register cache read failed\n");
return -EIO;
}
for (i = 0; i < ARRAY_SIZE(wm8400->reg_cache); i++)
wm8400->reg_cache[i] = be16_to_cpu(wm8400->reg_cache[i]);
/* If the codec is in reset use hard coded values */
if (!(wm8400->reg_cache[WM8400_POWER_MANAGEMENT_1] & WM8400_CODEC_ENA))
for (i = 0; i < ARRAY_SIZE(wm8400->reg_cache); i++)
if (reg_data[i].is_codec)
wm8400->reg_cache[i] = reg_data[i].default_val;
ret = wm8400_read(wm8400, WM8400_ID, 1, &reg);
if (ret != 0) {
dev_err(wm8400->dev, "ID register read failed: %d\n", ret);
return ret;
}
reg = (reg & WM8400_CHIP_REV_MASK) >> WM8400_CHIP_REV_SHIFT;
dev_info(wm8400->dev, "WM8400 revision %x\n", reg);
if (pdata && pdata->platform_init) {
ret = pdata->platform_init(wm8400->dev);
if (ret != 0)
dev_err(wm8400->dev, "Platform init failed: %d\n",
ret);
} else
dev_warn(wm8400->dev, "No platform initialisation supplied\n");
return ret;
}
static void wm8400_release(struct wm8400 *wm8400)
{
int i;
for (i = 0; i < ARRAY_SIZE(wm8400->regulators); i++)
if (wm8400->regulators[i].name)
platform_device_unregister(&wm8400->regulators[i]);
}
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
static int wm8400_i2c_read(void *io_data, char reg, int count, u16 *dest)
{
struct i2c_client *i2c = io_data;
struct i2c_msg xfer[2];
int ret;
/* Write register */
xfer[0].addr = i2c->addr;
xfer[0].flags = 0;
xfer[0].len = 1;
xfer[0].buf = &reg;
/* Read data */
xfer[1].addr = i2c->addr;
xfer[1].flags = I2C_M_RD;
xfer[1].len = count * sizeof(u16);
xfer[1].buf = (u8 *)dest;
ret = i2c_transfer(i2c->adapter, xfer, 2);
if (ret == 2)
ret = 0;
else if (ret >= 0)
ret = -EIO;
return ret;
}
static int wm8400_i2c_write(void *io_data, char reg, int count, const u16 *src)
{
struct i2c_client *i2c = io_data;
u8 *msg;
int ret;
/* We add 1 byte for device register - ideally I2C would gather. */
msg = kmalloc((count * sizeof(u16)) + 1, GFP_KERNEL);
if (msg == NULL)
return -ENOMEM;
msg[0] = reg;
memcpy(&msg[1], src, count * sizeof(u16));
ret = i2c_master_send(i2c, msg, (count * sizeof(u16)) + 1);
if (ret == (count * 2) + 1)
ret = 0;
else if (ret >= 0)
ret = -EIO;
kfree(msg);
return ret;
}
static int wm8400_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct wm8400 *wm8400;
int ret;
wm8400 = kzalloc(sizeof(struct wm8400), GFP_KERNEL);
if (wm8400 == NULL) {
ret = -ENOMEM;
goto err;
}
wm8400->io_data = i2c;
wm8400->read_dev = wm8400_i2c_read;
wm8400->write_dev = wm8400_i2c_write;
wm8400->dev = &i2c->dev;
i2c_set_clientdata(i2c, wm8400);
ret = wm8400_init(wm8400, i2c->dev.platform_data);
if (ret != 0)
goto struct_err;
return 0;
struct_err:
i2c_set_clientdata(i2c, NULL);
kfree(wm8400);
err:
return ret;
}
static int wm8400_i2c_remove(struct i2c_client *i2c)
{
struct wm8400 *wm8400 = i2c_get_clientdata(i2c);
wm8400_release(wm8400);
i2c_set_clientdata(i2c, NULL);
kfree(wm8400);
return 0;
}
static const struct i2c_device_id wm8400_i2c_id[] = {
{ "wm8400", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, wm8400_i2c_id);
static struct i2c_driver wm8400_i2c_driver = {
.driver = {
.name = "WM8400",
.owner = THIS_MODULE,
},
.probe = wm8400_i2c_probe,
.remove = wm8400_i2c_remove,
.id_table = wm8400_i2c_id,
};
#endif
static int __init wm8400_module_init(void)
{
int ret = -ENODEV;
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
ret = i2c_add_driver(&wm8400_i2c_driver);
if (ret != 0)
pr_err("Failed to register I2C driver: %d\n", ret);
#endif
return ret;
}
module_init(wm8400_module_init);
static void __exit wm8400_module_exit(void)
{
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
i2c_del_driver(&wm8400_i2c_driver);
#endif
}
module_exit(wm8400_module_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
......@@ -56,4 +56,28 @@ config REGULATOR_BQ24022
charging select between 100 mA and 500 mA charging current
limit.
config REGULATOR_WM8350
tristate "Wolfson Microelectroncis WM8350 AudioPlus PMIC"
depends on MFD_WM8350
select REGULATOR
help
This driver provides support for the voltage and current regulators
of the WM8350 AudioPlus PMIC.
config REGULATOR_WM8400
tristate "Wolfson Microelectroncis WM8400 AudioPlus PMIC"
depends on MFD_WM8400
select REGULATOR
help
This driver provides support for the voltage regulators of the
WM8400 AudioPlus PMIC.
config REGULATOR_DA903X
tristate "Support regulators on Dialog Semiconductor DA9030/DA9034 PMIC"
depends on PMIC_DA903X
select REGULATOR
help
Say y here to support the BUCKs and LDOs regulators found on
Dialog Semiconductor DA9030/DA9034 PMIC.
endmenu
......@@ -8,5 +8,8 @@ obj-$(CONFIG_REGULATOR_FIXED_VOLTAGE) += fixed.o
obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o
obj-$(CONFIG_REGULATOR_BQ24022) += bq24022.o
obj-$(CONFIG_REGULATOR_WM8350) += wm8350-regulator.o
obj-$(CONFIG_REGULATOR_WM8400) += wm8400-regulator.o
obj-$(CONFIG_REGULATOR_DA903X) += da903x.o
ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG
......@@ -18,13 +18,13 @@
#include <linux/regulator/bq24022.h>
#include <linux/regulator/driver.h>
static int bq24022_set_current_limit(struct regulator_dev *rdev,
int min_uA, int max_uA)
{
struct platform_device *pdev = rdev_get_drvdata(rdev);
struct bq24022_mach_info *pdata = pdev->dev.platform_data;
struct bq24022_mach_info *pdata = rdev_get_drvdata(rdev);
dev_dbg(&pdev->dev, "setting current limit to %s mA\n",
dev_dbg(rdev_get_dev(rdev), "setting current limit to %s mA\n",
max_uA >= 500000 ? "500" : "100");
/* REVISIT: maybe return error if min_uA != 0 ? */
......@@ -34,18 +34,16 @@ static int bq24022_set_current_limit(struct regulator_dev *rdev,
static int bq24022_get_current_limit(struct regulator_dev *rdev)
{
struct platform_device *pdev = rdev_get_drvdata(rdev);
struct bq24022_mach_info *pdata = pdev->dev.platform_data;
struct bq24022_mach_info *pdata = rdev_get_drvdata(rdev);
return gpio_get_value(pdata->gpio_iset2) ? 500000 : 100000;
}
static int bq24022_enable(struct regulator_dev *rdev)
{
struct platform_device *pdev = rdev_get_drvdata(rdev);
struct bq24022_mach_info *pdata = pdev->dev.platform_data;
struct bq24022_mach_info *pdata = rdev_get_drvdata(rdev);
dev_dbg(&pdev->dev, "enabling charger\n");
dev_dbg(rdev_get_dev(rdev), "enabling charger\n");
gpio_set_value(pdata->gpio_nce, 0);
return 0;
......@@ -53,10 +51,9 @@ static int bq24022_enable(struct regulator_dev *rdev)
static int bq24022_disable(struct regulator_dev *rdev)
{
struct platform_device *pdev = rdev_get_drvdata(rdev);
struct bq24022_mach_info *pdata = pdev->dev.platform_data;
struct bq24022_mach_info *pdata = rdev_get_drvdata(rdev);
dev_dbg(&pdev->dev, "disabling charger\n");
dev_dbg(rdev_get_dev(rdev), "disabling charger\n");
gpio_set_value(pdata->gpio_nce, 1);
return 0;
......@@ -108,7 +105,7 @@ static int __init bq24022_probe(struct platform_device *pdev)
ret = gpio_direction_output(pdata->gpio_iset2, 0);
ret = gpio_direction_output(pdata->gpio_nce, 1);
bq24022 = regulator_register(&bq24022_desc, pdev);
bq24022 = regulator_register(&bq24022_desc, &pdev->dev, pdata);
if (IS_ERR(bq24022)) {
dev_dbg(&pdev->dev, "couldn't register regulator\n");
ret = PTR_ERR(bq24022);
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
/*
* comparator.h -- Comparator Aux ADC for Wolfson WM8350 PMIC
*
* Copyright 2007 Wolfson Microelectronics PLC
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#ifndef __LINUX_MFD_WM8350_COMPARATOR_H_
#define __LINUX_MFD_WM8350_COMPARATOR_H_
/*
* Registers
*/
#define WM8350_DIGITISER_CONTROL_1 0x90
#define WM8350_DIGITISER_CONTROL_2 0x91
#define WM8350_AUX1_READBACK 0x98
#define WM8350_AUX2_READBACK 0x99
#define WM8350_AUX3_READBACK 0x9A
#define WM8350_AUX4_READBACK 0x9B
#define WM8350_CHIP_TEMP_READBACK 0x9F
#define WM8350_GENERIC_COMPARATOR_CONTROL 0xA3
#define WM8350_GENERIC_COMPARATOR_1 0xA4
#define WM8350_GENERIC_COMPARATOR_2 0xA5
#define WM8350_GENERIC_COMPARATOR_3 0xA6
#define WM8350_GENERIC_COMPARATOR_4 0xA7
/*
* R144 (0x90) - Digitiser Control (1)
*/
#define WM8350_AUXADC_CTC 0x4000
#define WM8350_AUXADC_POLL 0x2000
#define WM8350_AUXADC_HIB_MODE 0x1000
#define WM8350_AUXADC_SEL8 0x0080
#define WM8350_AUXADC_SEL7 0x0040
#define WM8350_AUXADC_SEL6 0x0020
#define WM8350_AUXADC_SEL5 0x0010
#define WM8350_AUXADC_SEL4 0x0008
#define WM8350_AUXADC_SEL3 0x0004
#define WM8350_AUXADC_SEL2 0x0002
#define WM8350_AUXADC_SEL1 0x0001
/*
* R145 (0x91) - Digitiser Control (2)
*/
#define WM8350_AUXADC_MASKMODE_MASK 0x3000
#define WM8350_AUXADC_CRATE_MASK 0x0700
#define WM8350_AUXADC_CAL 0x0004
#define WM8350_AUX_RBMODE 0x0002
#define WM8350_AUXADC_WAIT 0x0001
/*
* R152 (0x98) - AUX1 Readback
*/
#define WM8350_AUXADC_SCALE1_MASK 0x6000
#define WM8350_AUXADC_REF1 0x1000
#define WM8350_AUXADC_DATA1_MASK 0x0FFF
/*
* R153 (0x99) - AUX2 Readback
*/
#define WM8350_AUXADC_SCALE2_MASK 0x6000
#define WM8350_AUXADC_REF2 0x1000
#define WM8350_AUXADC_DATA2_MASK 0x0FFF
/*
* R154 (0x9A) - AUX3 Readback
*/
#define WM8350_AUXADC_SCALE3_MASK 0x6000
#define WM8350_AUXADC_REF3 0x1000
#define WM8350_AUXADC_DATA3_MASK 0x0FFF
/*
* R155 (0x9B) - AUX4 Readback
*/
#define WM8350_AUXADC_SCALE4_MASK 0x6000
#define WM8350_AUXADC_REF4 0x1000
#define WM8350_AUXADC_DATA4_MASK 0x0FFF
/*
* R156 (0x9C) - USB Voltage Readback
*/
#define WM8350_AUXADC_DATA_USB_MASK 0x0FFF
/*
* R157 (0x9D) - LINE Voltage Readback
*/
#define WM8350_AUXADC_DATA_LINE_MASK 0x0FFF
/*
* R158 (0x9E) - BATT Voltage Readback
*/
#define WM8350_AUXADC_DATA_BATT_MASK 0x0FFF
/*
* R159 (0x9F) - Chip Temp Readback
*/
#define WM8350_AUXADC_DATA_CHIPTEMP_MASK 0x0FFF
/*
* R163 (0xA3) - Generic Comparator Control
*/
#define WM8350_DCMP4_ENA 0x0008
#define WM8350_DCMP3_ENA 0x0004
#define WM8350_DCMP2_ENA 0x0002
#define WM8350_DCMP1_ENA 0x0001
/*
* R164 (0xA4) - Generic comparator 1
*/
#define WM8350_DCMP1_SRCSEL_MASK 0xE000
#define WM8350_DCMP1_GT 0x1000
#define WM8350_DCMP1_THR_MASK 0x0FFF
/*
* R165 (0xA5) - Generic comparator 2
*/
#define WM8350_DCMP2_SRCSEL_MASK 0xE000
#define WM8350_DCMP2_GT 0x1000
#define WM8350_DCMP2_THR_MASK 0x0FFF
/*
* R166 (0xA6) - Generic comparator 3
*/
#define WM8350_DCMP3_SRCSEL_MASK 0xE000
#define WM8350_DCMP3_GT 0x1000
#define WM8350_DCMP3_THR_MASK 0x0FFF
/*
* R167 (0xA7) - Generic comparator 4
*/
#define WM8350_DCMP4_SRCSEL_MASK 0xE000
#define WM8350_DCMP4_GT 0x1000
#define WM8350_DCMP4_THR_MASK 0x0FFF
/*
* Interrupts.
*/
#define WM8350_IRQ_AUXADC_DATARDY 16
#define WM8350_IRQ_AUXADC_DCOMP4 17
#define WM8350_IRQ_AUXADC_DCOMP3 18
#define WM8350_IRQ_AUXADC_DCOMP2 19
#define WM8350_IRQ_AUXADC_DCOMP1 20
#define WM8350_IRQ_SYS_HYST_COMP_FAIL 21
#define WM8350_IRQ_SYS_CHIP_GT115 22
#define WM8350_IRQ_SYS_CHIP_GT140 23
/*
* USB/2, LINE & BATT = ((VRTC * 2) / 4095)) * 10e6 uV
* Where VRTC = 2.7 V
*/
#define WM8350_AUX_COEFF 1319
#define WM8350_AUXADC_AUX1 0
#define WM8350_AUXADC_AUX2 1
#define WM8350_AUXADC_AUX3 2
#define WM8350_AUXADC_AUX4 3
#define WM8350_AUXADC_USB 4
#define WM8350_AUXADC_LINE 5
#define WM8350_AUXADC_BATT 6
#define WM8350_AUXADC_TEMP 7
#endif
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
/*
* supply.h -- Power Supply Driver for Wolfson WM8350 PMIC
*
* Copyright 2007 Wolfson Microelectronics PLC
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
*/
#ifndef __LINUX_MFD_WM8350_SUPPLY_H_
#define __LINUX_MFD_WM8350_SUPPLY_H_
#include <linux/platform_device.h>
/*
* Charger registers
*/
#define WM8350_BATTERY_CHARGER_CONTROL_1 0xA8
#define WM8350_BATTERY_CHARGER_CONTROL_2 0xA9
#define WM8350_BATTERY_CHARGER_CONTROL_3 0xAA
/*
* R168 (0xA8) - Battery Charger Control 1
*/
#define WM8350_CHG_ENA_R168 0x8000
#define WM8350_CHG_THR 0x2000
#define WM8350_CHG_EOC_SEL_MASK 0x1C00
#define WM8350_CHG_TRICKLE_TEMP_CHOKE 0x0200
#define WM8350_CHG_TRICKLE_USB_CHOKE 0x0100
#define WM8350_CHG_RECOVER_T 0x0080
#define WM8350_CHG_END_ACT 0x0040
#define WM8350_CHG_FAST 0x0020
#define WM8350_CHG_FAST_USB_THROTTLE 0x0010
#define WM8350_CHG_NTC_MON 0x0008
#define WM8350_CHG_BATT_HOT_MON 0x0004
#define WM8350_CHG_BATT_COLD_MON 0x0002
#define WM8350_CHG_CHIP_TEMP_MON 0x0001
/*
* R169 (0xA9) - Battery Charger Control 2
*/
#define WM8350_CHG_ACTIVE 0x8000
#define WM8350_CHG_PAUSE 0x4000
#define WM8350_CHG_STS_MASK 0x3000
#define WM8350_CHG_TIME_MASK 0x0F00
#define WM8350_CHG_MASK_WALL_FB 0x0080
#define WM8350_CHG_TRICKLE_SEL 0x0040
#define WM8350_CHG_VSEL_MASK 0x0030
#define WM8350_CHG_ISEL_MASK 0x000F
#define WM8350_CHG_STS_OFF 0x0000
#define WM8350_CHG_STS_TRICKLE 0x1000
#define WM8350_CHG_STS_FAST 0x2000
/*
* R170 (0xAA) - Battery Charger Control 3
*/
#define WM8350_CHG_THROTTLE_T_MASK 0x0060
#define WM8350_CHG_SMART 0x0010
#define WM8350_CHG_TIMER_ADJT_MASK 0x000F
/*
* Charger Interrupts
*/
#define WM8350_IRQ_CHG_BAT_HOT 0
#define WM8350_IRQ_CHG_BAT_COLD 1
#define WM8350_IRQ_CHG_BAT_FAIL 2
#define WM8350_IRQ_CHG_TO 3
#define WM8350_IRQ_CHG_END 4
#define WM8350_IRQ_CHG_START 5
#define WM8350_IRQ_CHG_FAST_RDY 6
#define WM8350_IRQ_CHG_VBATT_LT_3P9 10
#define WM8350_IRQ_CHG_VBATT_LT_3P1 11
#define WM8350_IRQ_CHG_VBATT_LT_2P85 12
/*
* Charger Policy
*/
#define WM8350_CHG_TRICKLE_50mA (0 << 6)
#define WM8350_CHG_TRICKLE_100mA (1 << 6)
#define WM8350_CHG_4_05V (0 << 4)
#define WM8350_CHG_4_10V (1 << 4)
#define WM8350_CHG_4_15V (2 << 4)
#define WM8350_CHG_4_20V (3 << 4)
#define WM8350_CHG_FAST_LIMIT_mA(x) ((x / 50) & 0xf)
#define WM8350_CHG_EOC_mA(x) (((x - 10) & 0x7) << 10)
#define WM8350_CHG_TRICKLE_3_1V (0 << 13)
#define WM8350_CHG_TRICKLE_3_9V (1 << 13)
/*
* Supply Registers.
*/
#define WM8350_USB_VOLTAGE_READBACK 0x9C
#define WM8350_LINE_VOLTAGE_READBACK 0x9D
#define WM8350_BATT_VOLTAGE_READBACK 0x9E
/*
* Supply Interrupts.
*/
#define WM8350_IRQ_USB_LIMIT 15
#define WM8350_IRQ_EXT_USB_FB 36
#define WM8350_IRQ_EXT_WALL_FB 37
#define WM8350_IRQ_EXT_BAT_FB 38
struct wm8350_power {
struct platform_device *pdev;
};
#endif
/*
* wdt.h -- Watchdog Driver for Wolfson WM8350 PMIC
*
* Copyright 2007, 2008 Wolfson Microelectronics PLC
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#ifndef __LINUX_MFD_WM8350_WDT_H_
#define __LINUX_MFD_WM8350_WDT_H_
#include <linux/platform_device.h>
#define WM8350_WDOG_HIB_MODE 0x0080
#define WM8350_WDOG_DEBUG 0x0040
#define WM8350_WDOG_MODE_MASK 0x0030
#define WM8350_WDOG_TO_MASK 0x0007
#define WM8350_IRQ_SYS_WDOG_TO 24
struct wm8350_wdt {
struct platform_device *pdev;
};
#endif
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册