Commit e5b48684 authored by Mark Brown's avatar Mark Brown Committed by Samuel Ortiz
Browse files

mfd: Factor out WM831x I2C I/O from the core driver



In preparation for the addition of SPI support for the WM831x move the I2C
specific code into a separate file with a separate Kconfig option so the
I2C support can be excluded from the build.

Also update the 1133-EV1 PMIC module support for SMDK6410 to use the new
symbol.

Signed-off-by: default avatarMark Brown <broonie@opensource.wolfsonmicro.com>
Signed-off-by: default avatarSamuel Ortiz <sameo@linux.intel.com>
parent 00969f23
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -185,6 +185,7 @@ config SMDK6410_WM1192_EV1
	select REGULATOR_WM831X
	select S3C24XX_GPIO_EXTRA64
	select MFD_WM831X
	select MFD_WM831X_I2C
	help
	  The Wolfson Microelectronics 1192-EV1 is a WM831x based PMIC
	  daughtercard for the Samsung SMDK6410 reference platform.
+10 −5
Original line number Diff line number Diff line
@@ -315,14 +315,19 @@ config MFD_WM8400
	  the functionality of the device.

config MFD_WM831X
	bool "Support Wolfson Microelectronics WM831x/2x PMICs"
	bool
	depends on GENERIC_HARDIRQS

config MFD_WM831X_I2C
	bool "Support Wolfson Microelectronics WM831x/2x PMICs with I2C"
	select MFD_CORE
	select MFD_WM831X
	depends on I2C=y && GENERIC_HARDIRQS
	help
	  Support for the Wolfson Microelecronics WM831x and WM832x PMICs.
	  This driver provides common support for accessing the device,
	  additional drivers must be enabled in order to use the
	  functionality of the device.
	  Support for the Wolfson Microelecronics WM831x and WM832x PMICs
	  when controlled using I2C.  This driver provides common support
	  for accessing the device, additional drivers must be enabled in
	  order to use the functionality of the device.

config MFD_WM8350
	bool
+1 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ obj-$(CONFIG_MFD_TC6393XB) += tc6393xb.o tmio_core.o
obj-$(CONFIG_MFD_WM8400)	+= wm8400-core.o
wm831x-objs			:= wm831x-core.o wm831x-irq.o wm831x-otp.o
obj-$(CONFIG_MFD_WM831X)	+= wm831x.o
obj-$(CONFIG_MFD_WM831X_I2C)	+= wm831x-i2c.o
wm8350-objs			:= wm8350-core.o wm8350-regmap.o wm8350-gpio.o
wm8350-objs			+= wm8350-irq.o
obj-$(CONFIG_MFD_WM8350)	+= wm8350.o
+4 −134
Original line number Diff line number Diff line
@@ -14,7 +14,6 @@

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/bcd.h>
#include <linux/delay.h>
#include <linux/mfd/core.h>
@@ -90,15 +89,6 @@ int wm831x_isinkv_values[WM831X_ISINK_MAX_ISEL + 1] = {
};
EXPORT_SYMBOL_GPL(wm831x_isinkv_values);

enum wm831x_parent {
	WM8310 = 0x8310,
	WM8311 = 0x8311,
	WM8312 = 0x8312,
	WM8320 = 0x8320,
	WM8321 = 0x8321,
	WM8325 = 0x8325,
};

static int wm831x_reg_locked(struct wm831x *wm831x, unsigned short reg)
{
	if (!wm831x->locked)
@@ -1447,7 +1437,7 @@ static struct mfd_cell backlight_devs[] = {
/*
 * Instantiate the generic non-control parts of the device.
 */
static int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
{
	struct wm831x_pdata *pdata = wm831x->dev->platform_data;
	int rev;
@@ -1673,7 +1663,7 @@ err:
	return ret;
}

static void wm831x_device_exit(struct wm831x *wm831x)
void wm831x_device_exit(struct wm831x *wm831x)
{
	wm831x_otp_exit(wm831x);
	mfd_remove_devices(wm831x->dev);
@@ -1683,7 +1673,7 @@ static void wm831x_device_exit(struct wm831x *wm831x)
	kfree(wm831x);
}

static int wm831x_device_suspend(struct wm831x *wm831x)
int wm831x_device_suspend(struct wm831x *wm831x)
{
	int reg, mask;

@@ -1719,126 +1709,6 @@ static int wm831x_device_suspend(struct wm831x *wm831x)
	return 0;
}

static int wm831x_i2c_read_device(struct wm831x *wm831x, unsigned short reg,
				  int bytes, void *dest)
{
	struct i2c_client *i2c = wm831x->control_data;
	int ret;
	u16 r = cpu_to_be16(reg);

	ret = i2c_master_send(i2c, (unsigned char *)&r, 2);
	if (ret < 0)
		return ret;
	if (ret != 2)
		return -EIO;

	ret = i2c_master_recv(i2c, dest, bytes);
	if (ret < 0)
		return ret;
	if (ret != bytes)
		return -EIO;
	return 0;
}

/* Currently we allocate the write buffer on the stack; this is OK for
 * small writes - if we need to do large writes this will need to be
 * revised.
 */
static int wm831x_i2c_write_device(struct wm831x *wm831x, unsigned short reg,
				   int bytes, void *src)
{
	struct i2c_client *i2c = wm831x->control_data;
	unsigned char msg[bytes + 2];
	int ret;

	reg = cpu_to_be16(reg);
	memcpy(&msg[0], &reg, 2);
	memcpy(&msg[2], src, bytes);

	ret = i2c_master_send(i2c, msg, bytes + 2);
	if (ret < 0)
		return ret;
	if (ret < bytes + 2)
		return -EIO;

	return 0;
}

static int wm831x_i2c_probe(struct i2c_client *i2c,
			    const struct i2c_device_id *id)
{
	struct wm831x *wm831x;

	wm831x = kzalloc(sizeof(struct wm831x), GFP_KERNEL);
	if (wm831x == NULL)
		return -ENOMEM;

	i2c_set_clientdata(i2c, wm831x);
	wm831x->dev = &i2c->dev;
	wm831x->control_data = i2c;
	wm831x->read_dev = wm831x_i2c_read_device;
	wm831x->write_dev = wm831x_i2c_write_device;

	return wm831x_device_init(wm831x, id->driver_data, i2c->irq);
}

static int wm831x_i2c_remove(struct i2c_client *i2c)
{
	struct wm831x *wm831x = i2c_get_clientdata(i2c);

	wm831x_device_exit(wm831x);

	return 0;
}

static int wm831x_i2c_suspend(struct i2c_client *i2c, pm_message_t mesg)
{
	struct wm831x *wm831x = i2c_get_clientdata(i2c);

	return wm831x_device_suspend(wm831x);
}

static const struct i2c_device_id wm831x_i2c_id[] = {
	{ "wm8310", WM8310 },
	{ "wm8311", WM8311 },
	{ "wm8312", WM8312 },
	{ "wm8320", WM8320 },
	{ "wm8321", WM8321 },
	{ "wm8325", WM8325 },
	{ }
};
MODULE_DEVICE_TABLE(i2c, wm831x_i2c_id);


static struct i2c_driver wm831x_i2c_driver = {
	.driver = {
		   .name = "wm831x",
		   .owner = THIS_MODULE,
	},
	.probe = wm831x_i2c_probe,
	.remove = wm831x_i2c_remove,
	.suspend = wm831x_i2c_suspend,
	.id_table = wm831x_i2c_id,
};

static int __init wm831x_i2c_init(void)
{
	int ret;

	ret = i2c_add_driver(&wm831x_i2c_driver);
	if (ret != 0)
		pr_err("Failed to register wm831x I2C driver: %d\n", ret);

	return ret;
}
subsys_initcall(wm831x_i2c_init);

static void __exit wm831x_i2c_exit(void)
{
	i2c_del_driver(&wm831x_i2c_driver);
}
module_exit(wm831x_i2c_exit);

MODULE_DESCRIPTION("I2C support for the WM831X AudioPlus PMIC");
MODULE_DESCRIPTION("Core support for the WM831X AudioPlus PMIC");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Mark Brown");
+143 −0
Original line number Diff line number Diff line
/*
 * wm831x-i2c.c  --  I2C access for Wolfson WM831x PMICs
 *
 * Copyright 2009,2010 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/kernel.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/mfd/core.h>
#include <linux/slab.h>

#include <linux/mfd/wm831x/core.h>
#include <linux/mfd/wm831x/pdata.h>

static int wm831x_i2c_read_device(struct wm831x *wm831x, unsigned short reg,
				  int bytes, void *dest)
{
	struct i2c_client *i2c = wm831x->control_data;
	int ret;
	u16 r = cpu_to_be16(reg);

	ret = i2c_master_send(i2c, (unsigned char *)&r, 2);
	if (ret < 0)
		return ret;
	if (ret != 2)
		return -EIO;

	ret = i2c_master_recv(i2c, dest, bytes);
	if (ret < 0)
		return ret;
	if (ret != bytes)
		return -EIO;
	return 0;
}

/* Currently we allocate the write buffer on the stack; this is OK for
 * small writes - if we need to do large writes this will need to be
 * revised.
 */
static int wm831x_i2c_write_device(struct wm831x *wm831x, unsigned short reg,
				   int bytes, void *src)
{
	struct i2c_client *i2c = wm831x->control_data;
	unsigned char msg[bytes + 2];
	int ret;

	reg = cpu_to_be16(reg);
	memcpy(&msg[0], &reg, 2);
	memcpy(&msg[2], src, bytes);

	ret = i2c_master_send(i2c, msg, bytes + 2);
	if (ret < 0)
		return ret;
	if (ret < bytes + 2)
		return -EIO;

	return 0;
}

static int wm831x_i2c_probe(struct i2c_client *i2c,
			    const struct i2c_device_id *id)
{
	struct wm831x *wm831x;

	wm831x = kzalloc(sizeof(struct wm831x), GFP_KERNEL);
	if (wm831x == NULL)
		return -ENOMEM;

	i2c_set_clientdata(i2c, wm831x);
	wm831x->dev = &i2c->dev;
	wm831x->control_data = i2c;
	wm831x->read_dev = wm831x_i2c_read_device;
	wm831x->write_dev = wm831x_i2c_write_device;

	return wm831x_device_init(wm831x, id->driver_data, i2c->irq);
}

static int wm831x_i2c_remove(struct i2c_client *i2c)
{
	struct wm831x *wm831x = i2c_get_clientdata(i2c);

	wm831x_device_exit(wm831x);

	return 0;
}

static int wm831x_i2c_suspend(struct i2c_client *i2c, pm_message_t mesg)
{
	struct wm831x *wm831x = i2c_get_clientdata(i2c);

	return wm831x_device_suspend(wm831x);
}

static const struct i2c_device_id wm831x_i2c_id[] = {
	{ "wm8310", WM8310 },
	{ "wm8311", WM8311 },
	{ "wm8312", WM8312 },
	{ "wm8320", WM8320 },
	{ "wm8321", WM8321 },
	{ "wm8325", WM8325 },
	{ }
};
MODULE_DEVICE_TABLE(i2c, wm831x_i2c_id);


static struct i2c_driver wm831x_i2c_driver = {
	.driver = {
		   .name = "wm831x",
		   .owner = THIS_MODULE,
	},
	.probe = wm831x_i2c_probe,
	.remove = wm831x_i2c_remove,
	.suspend = wm831x_i2c_suspend,
	.id_table = wm831x_i2c_id,
};

static int __init wm831x_i2c_init(void)
{
	int ret;

	ret = i2c_add_driver(&wm831x_i2c_driver);
	if (ret != 0)
		pr_err("Failed to register wm831x I2C driver: %d\n", ret);

	return ret;
}
subsys_initcall(wm831x_i2c_init);

static void __exit wm831x_i2c_exit(void)
{
	i2c_del_driver(&wm831x_i2c_driver);
}
module_exit(wm831x_i2c_exit);
Loading