Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fec4fe26 authored by Mark Brown's avatar Mark Brown
Browse files

Merge branch 'regmap-mfd' into regmap-next

parents ae130d22 50eeef5d
Loading
Loading
Loading
Loading
+3 −0
Original line number Original line Diff line number Diff line
@@ -404,6 +404,7 @@ config MFD_WM831X_I2C
	bool "Support Wolfson Microelectronics WM831x/2x PMICs with I2C"
	bool "Support Wolfson Microelectronics WM831x/2x PMICs with I2C"
	select MFD_CORE
	select MFD_CORE
	select MFD_WM831X
	select MFD_WM831X
	select REGMAP_I2C
	depends on I2C=y && GENERIC_HARDIRQS
	depends on I2C=y && GENERIC_HARDIRQS
	help
	help
	  Support for the Wolfson Microelecronics WM831x and WM832x PMICs
	  Support for the Wolfson Microelecronics WM831x and WM832x PMICs
@@ -415,6 +416,7 @@ config MFD_WM831X_SPI
	bool "Support Wolfson Microelectronics WM831x/2x PMICs with SPI"
	bool "Support Wolfson Microelectronics WM831x/2x PMICs with SPI"
	select MFD_CORE
	select MFD_CORE
	select MFD_WM831X
	select MFD_WM831X
	select REGMAP_SPI
	depends on SPI_MASTER && GENERIC_HARDIRQS
	depends on SPI_MASTER && GENERIC_HARDIRQS
	help
	help
	  Support for the Wolfson Microelecronics WM831x and WM832x PMICs
	  Support for the Wolfson Microelecronics WM831x and WM832x PMICs
@@ -488,6 +490,7 @@ config MFD_WM8350_I2C
config MFD_WM8994
config MFD_WM8994
	bool "Support Wolfson Microelectronics WM8994"
	bool "Support Wolfson Microelectronics WM8994"
	select MFD_CORE
	select MFD_CORE
	select REGMAP_I2C
	depends on I2C=y && GENERIC_HARDIRQS
	depends on I2C=y && GENERIC_HARDIRQS
	help
	help
	  The WM8994 is a highly integrated hi-fi CODEC designed for
	  The WM8994 is a highly integrated hi-fi CODEC designed for
+371 −53
Original line number Original line Diff line number Diff line
@@ -18,6 +18,7 @@
#include <linux/delay.h>
#include <linux/delay.h>
#include <linux/mfd/core.h>
#include <linux/mfd/core.h>
#include <linux/slab.h>
#include <linux/slab.h>
#include <linux/err.h>


#include <linux/mfd/wm831x/core.h>
#include <linux/mfd/wm831x/core.h>
#include <linux/mfd/wm831x/pdata.h>
#include <linux/mfd/wm831x/pdata.h>
@@ -160,27 +161,350 @@ int wm831x_reg_unlock(struct wm831x *wm831x)
}
}
EXPORT_SYMBOL_GPL(wm831x_reg_unlock);
EXPORT_SYMBOL_GPL(wm831x_reg_unlock);


static int wm831x_read(struct wm831x *wm831x, unsigned short reg,
static bool wm831x_reg_readable(struct device *dev, unsigned int reg)
		       int bytes, void *dest)
{
{
	int ret, i;
	switch (reg) {
	u16 *buf = dest;
	case WM831X_RESET_ID:

	case WM831X_REVISION:
	BUG_ON(bytes % 2);
	case WM831X_PARENT_ID:
	BUG_ON(bytes <= 0);
	case WM831X_SYSVDD_CONTROL:
	case WM831X_THERMAL_MONITORING:
	case WM831X_POWER_STATE:
	case WM831X_WATCHDOG:
	case WM831X_ON_PIN_CONTROL:
	case WM831X_RESET_CONTROL:
	case WM831X_CONTROL_INTERFACE:
	case WM831X_SECURITY_KEY:
	case WM831X_SOFTWARE_SCRATCH:
	case WM831X_OTP_CONTROL:
	case WM831X_GPIO_LEVEL:
	case WM831X_SYSTEM_STATUS:
	case WM831X_ON_SOURCE:
	case WM831X_OFF_SOURCE:
	case WM831X_SYSTEM_INTERRUPTS:
	case WM831X_INTERRUPT_STATUS_1:
	case WM831X_INTERRUPT_STATUS_2:
	case WM831X_INTERRUPT_STATUS_3:
	case WM831X_INTERRUPT_STATUS_4:
	case WM831X_INTERRUPT_STATUS_5:
	case WM831X_IRQ_CONFIG:
	case WM831X_SYSTEM_INTERRUPTS_MASK:
	case WM831X_INTERRUPT_STATUS_1_MASK:
	case WM831X_INTERRUPT_STATUS_2_MASK:
	case WM831X_INTERRUPT_STATUS_3_MASK:
	case WM831X_INTERRUPT_STATUS_4_MASK:
	case WM831X_INTERRUPT_STATUS_5_MASK:
	case WM831X_RTC_WRITE_COUNTER:
	case WM831X_RTC_TIME_1:
	case WM831X_RTC_TIME_2:
	case WM831X_RTC_ALARM_1:
	case WM831X_RTC_ALARM_2:
	case WM831X_RTC_CONTROL:
	case WM831X_RTC_TRIM:
	case WM831X_TOUCH_CONTROL_1:
	case WM831X_TOUCH_CONTROL_2:
	case WM831X_TOUCH_DATA_X:
	case WM831X_TOUCH_DATA_Y:
	case WM831X_TOUCH_DATA_Z:
	case WM831X_AUXADC_DATA:
	case WM831X_AUXADC_CONTROL:
	case WM831X_AUXADC_SOURCE:
	case WM831X_COMPARATOR_CONTROL:
	case WM831X_COMPARATOR_1:
	case WM831X_COMPARATOR_2:
	case WM831X_COMPARATOR_3:
	case WM831X_COMPARATOR_4:
	case WM831X_GPIO1_CONTROL:
	case WM831X_GPIO2_CONTROL:
	case WM831X_GPIO3_CONTROL:
	case WM831X_GPIO4_CONTROL:
	case WM831X_GPIO5_CONTROL:
	case WM831X_GPIO6_CONTROL:
	case WM831X_GPIO7_CONTROL:
	case WM831X_GPIO8_CONTROL:
	case WM831X_GPIO9_CONTROL:
	case WM831X_GPIO10_CONTROL:
	case WM831X_GPIO11_CONTROL:
	case WM831X_GPIO12_CONTROL:
	case WM831X_GPIO13_CONTROL:
	case WM831X_GPIO14_CONTROL:
	case WM831X_GPIO15_CONTROL:
	case WM831X_GPIO16_CONTROL:
	case WM831X_CHARGER_CONTROL_1:
	case WM831X_CHARGER_CONTROL_2:
	case WM831X_CHARGER_STATUS:
	case WM831X_BACKUP_CHARGER_CONTROL:
	case WM831X_STATUS_LED_1:
	case WM831X_STATUS_LED_2:
	case WM831X_CURRENT_SINK_1:
	case WM831X_CURRENT_SINK_2:
	case WM831X_DCDC_ENABLE:
	case WM831X_LDO_ENABLE:
	case WM831X_DCDC_STATUS:
	case WM831X_LDO_STATUS:
	case WM831X_DCDC_UV_STATUS:
	case WM831X_LDO_UV_STATUS:
	case WM831X_DC1_CONTROL_1:
	case WM831X_DC1_CONTROL_2:
	case WM831X_DC1_ON_CONFIG:
	case WM831X_DC1_SLEEP_CONTROL:
	case WM831X_DC1_DVS_CONTROL:
	case WM831X_DC2_CONTROL_1:
	case WM831X_DC2_CONTROL_2:
	case WM831X_DC2_ON_CONFIG:
	case WM831X_DC2_SLEEP_CONTROL:
	case WM831X_DC2_DVS_CONTROL:
	case WM831X_DC3_CONTROL_1:
	case WM831X_DC3_CONTROL_2:
	case WM831X_DC3_ON_CONFIG:
	case WM831X_DC3_SLEEP_CONTROL:
	case WM831X_DC4_CONTROL:
	case WM831X_DC4_SLEEP_CONTROL:
	case WM831X_EPE1_CONTROL:
	case WM831X_EPE2_CONTROL:
	case WM831X_LDO1_CONTROL:
	case WM831X_LDO1_ON_CONTROL:
	case WM831X_LDO1_SLEEP_CONTROL:
	case WM831X_LDO2_CONTROL:
	case WM831X_LDO2_ON_CONTROL:
	case WM831X_LDO2_SLEEP_CONTROL:
	case WM831X_LDO3_CONTROL:
	case WM831X_LDO3_ON_CONTROL:
	case WM831X_LDO3_SLEEP_CONTROL:
	case WM831X_LDO4_CONTROL:
	case WM831X_LDO4_ON_CONTROL:
	case WM831X_LDO4_SLEEP_CONTROL:
	case WM831X_LDO5_CONTROL:
	case WM831X_LDO5_ON_CONTROL:
	case WM831X_LDO5_SLEEP_CONTROL:
	case WM831X_LDO6_CONTROL:
	case WM831X_LDO6_ON_CONTROL:
	case WM831X_LDO6_SLEEP_CONTROL:
	case WM831X_LDO7_CONTROL:
	case WM831X_LDO7_ON_CONTROL:
	case WM831X_LDO7_SLEEP_CONTROL:
	case WM831X_LDO8_CONTROL:
	case WM831X_LDO8_ON_CONTROL:
	case WM831X_LDO8_SLEEP_CONTROL:
	case WM831X_LDO9_CONTROL:
	case WM831X_LDO9_ON_CONTROL:
	case WM831X_LDO9_SLEEP_CONTROL:
	case WM831X_LDO10_CONTROL:
	case WM831X_LDO10_ON_CONTROL:
	case WM831X_LDO10_SLEEP_CONTROL:
	case WM831X_LDO11_ON_CONTROL:
	case WM831X_LDO11_SLEEP_CONTROL:
	case WM831X_POWER_GOOD_SOURCE_1:
	case WM831X_POWER_GOOD_SOURCE_2:
	case WM831X_CLOCK_CONTROL_1:
	case WM831X_CLOCK_CONTROL_2:
	case WM831X_FLL_CONTROL_1:
	case WM831X_FLL_CONTROL_2:
	case WM831X_FLL_CONTROL_3:
	case WM831X_FLL_CONTROL_4:
	case WM831X_FLL_CONTROL_5:
	case WM831X_UNIQUE_ID_1:
	case WM831X_UNIQUE_ID_2:
	case WM831X_UNIQUE_ID_3:
	case WM831X_UNIQUE_ID_4:
	case WM831X_UNIQUE_ID_5:
	case WM831X_UNIQUE_ID_6:
	case WM831X_UNIQUE_ID_7:
	case WM831X_UNIQUE_ID_8:
	case WM831X_FACTORY_OTP_ID:
	case WM831X_FACTORY_OTP_1:
	case WM831X_FACTORY_OTP_2:
	case WM831X_FACTORY_OTP_3:
	case WM831X_FACTORY_OTP_4:
	case WM831X_FACTORY_OTP_5:
	case WM831X_CUSTOMER_OTP_ID:
	case WM831X_DC1_OTP_CONTROL:
	case WM831X_DC2_OTP_CONTROL:
	case WM831X_DC3_OTP_CONTROL:
	case WM831X_LDO1_2_OTP_CONTROL:
	case WM831X_LDO3_4_OTP_CONTROL:
	case WM831X_LDO5_6_OTP_CONTROL:
	case WM831X_LDO7_8_OTP_CONTROL:
	case WM831X_LDO9_10_OTP_CONTROL:
	case WM831X_LDO11_EPE_CONTROL:
	case WM831X_GPIO1_OTP_CONTROL:
	case WM831X_GPIO2_OTP_CONTROL:
	case WM831X_GPIO3_OTP_CONTROL:
	case WM831X_GPIO4_OTP_CONTROL:
	case WM831X_GPIO5_OTP_CONTROL:
	case WM831X_GPIO6_OTP_CONTROL:
	case WM831X_DBE_CHECK_DATA:
		return true;
	default:
		return false;
	}
}


	ret = wm831x->read_dev(wm831x, reg, bytes, dest);
static bool wm831x_reg_writeable(struct device *dev, unsigned int reg)
	if (ret < 0)
{
		return ret;
	struct wm831x *wm831x = dev_get_drvdata(dev);


	for (i = 0; i < bytes / 2; i++) {
	if (wm831x_reg_locked(wm831x, reg))
		buf[i] = be16_to_cpu(buf[i]);
		return false;


		dev_vdbg(wm831x->dev, "Read %04x from R%d(0x%x)\n",
	switch (reg) {
			 buf[i], reg + i, reg + i);
	case WM831X_SYSVDD_CONTROL:
	case WM831X_THERMAL_MONITORING:
	case WM831X_POWER_STATE:
	case WM831X_WATCHDOG:
	case WM831X_ON_PIN_CONTROL:
	case WM831X_RESET_CONTROL:
	case WM831X_CONTROL_INTERFACE:
	case WM831X_SECURITY_KEY:
	case WM831X_SOFTWARE_SCRATCH:
	case WM831X_OTP_CONTROL:
	case WM831X_GPIO_LEVEL:
	case WM831X_INTERRUPT_STATUS_1:
	case WM831X_INTERRUPT_STATUS_2:
	case WM831X_INTERRUPT_STATUS_3:
	case WM831X_INTERRUPT_STATUS_4:
	case WM831X_INTERRUPT_STATUS_5:
	case WM831X_IRQ_CONFIG:
	case WM831X_SYSTEM_INTERRUPTS_MASK:
	case WM831X_INTERRUPT_STATUS_1_MASK:
	case WM831X_INTERRUPT_STATUS_2_MASK:
	case WM831X_INTERRUPT_STATUS_3_MASK:
	case WM831X_INTERRUPT_STATUS_4_MASK:
	case WM831X_INTERRUPT_STATUS_5_MASK:
	case WM831X_RTC_TIME_1:
	case WM831X_RTC_TIME_2:
	case WM831X_RTC_ALARM_1:
	case WM831X_RTC_ALARM_2:
	case WM831X_RTC_CONTROL:
	case WM831X_RTC_TRIM:
	case WM831X_TOUCH_CONTROL_1:
	case WM831X_TOUCH_CONTROL_2:
	case WM831X_AUXADC_CONTROL:
	case WM831X_AUXADC_SOURCE:
	case WM831X_COMPARATOR_CONTROL:
	case WM831X_COMPARATOR_1:
	case WM831X_COMPARATOR_2:
	case WM831X_COMPARATOR_3:
	case WM831X_COMPARATOR_4:
	case WM831X_GPIO1_CONTROL:
	case WM831X_GPIO2_CONTROL:
	case WM831X_GPIO3_CONTROL:
	case WM831X_GPIO4_CONTROL:
	case WM831X_GPIO5_CONTROL:
	case WM831X_GPIO6_CONTROL:
	case WM831X_GPIO7_CONTROL:
	case WM831X_GPIO8_CONTROL:
	case WM831X_GPIO9_CONTROL:
	case WM831X_GPIO10_CONTROL:
	case WM831X_GPIO11_CONTROL:
	case WM831X_GPIO12_CONTROL:
	case WM831X_GPIO13_CONTROL:
	case WM831X_GPIO14_CONTROL:
	case WM831X_GPIO15_CONTROL:
	case WM831X_GPIO16_CONTROL:
	case WM831X_CHARGER_CONTROL_1:
	case WM831X_CHARGER_CONTROL_2:
	case WM831X_CHARGER_STATUS:
	case WM831X_BACKUP_CHARGER_CONTROL:
	case WM831X_STATUS_LED_1:
	case WM831X_STATUS_LED_2:
	case WM831X_CURRENT_SINK_1:
	case WM831X_CURRENT_SINK_2:
	case WM831X_DCDC_ENABLE:
	case WM831X_LDO_ENABLE:
	case WM831X_DC1_CONTROL_1:
	case WM831X_DC1_CONTROL_2:
	case WM831X_DC1_ON_CONFIG:
	case WM831X_DC1_SLEEP_CONTROL:
	case WM831X_DC1_DVS_CONTROL:
	case WM831X_DC2_CONTROL_1:
	case WM831X_DC2_CONTROL_2:
	case WM831X_DC2_ON_CONFIG:
	case WM831X_DC2_SLEEP_CONTROL:
	case WM831X_DC2_DVS_CONTROL:
	case WM831X_DC3_CONTROL_1:
	case WM831X_DC3_CONTROL_2:
	case WM831X_DC3_ON_CONFIG:
	case WM831X_DC3_SLEEP_CONTROL:
	case WM831X_DC4_CONTROL:
	case WM831X_DC4_SLEEP_CONTROL:
	case WM831X_EPE1_CONTROL:
	case WM831X_EPE2_CONTROL:
	case WM831X_LDO1_CONTROL:
	case WM831X_LDO1_ON_CONTROL:
	case WM831X_LDO1_SLEEP_CONTROL:
	case WM831X_LDO2_CONTROL:
	case WM831X_LDO2_ON_CONTROL:
	case WM831X_LDO2_SLEEP_CONTROL:
	case WM831X_LDO3_CONTROL:
	case WM831X_LDO3_ON_CONTROL:
	case WM831X_LDO3_SLEEP_CONTROL:
	case WM831X_LDO4_CONTROL:
	case WM831X_LDO4_ON_CONTROL:
	case WM831X_LDO4_SLEEP_CONTROL:
	case WM831X_LDO5_CONTROL:
	case WM831X_LDO5_ON_CONTROL:
	case WM831X_LDO5_SLEEP_CONTROL:
	case WM831X_LDO6_CONTROL:
	case WM831X_LDO6_ON_CONTROL:
	case WM831X_LDO6_SLEEP_CONTROL:
	case WM831X_LDO7_CONTROL:
	case WM831X_LDO7_ON_CONTROL:
	case WM831X_LDO7_SLEEP_CONTROL:
	case WM831X_LDO8_CONTROL:
	case WM831X_LDO8_ON_CONTROL:
	case WM831X_LDO8_SLEEP_CONTROL:
	case WM831X_LDO9_CONTROL:
	case WM831X_LDO9_ON_CONTROL:
	case WM831X_LDO9_SLEEP_CONTROL:
	case WM831X_LDO10_CONTROL:
	case WM831X_LDO10_ON_CONTROL:
	case WM831X_LDO10_SLEEP_CONTROL:
	case WM831X_LDO11_ON_CONTROL:
	case WM831X_LDO11_SLEEP_CONTROL:
	case WM831X_POWER_GOOD_SOURCE_1:
	case WM831X_POWER_GOOD_SOURCE_2:
	case WM831X_CLOCK_CONTROL_1:
	case WM831X_CLOCK_CONTROL_2:
	case WM831X_FLL_CONTROL_1:
	case WM831X_FLL_CONTROL_2:
	case WM831X_FLL_CONTROL_3:
	case WM831X_FLL_CONTROL_4:
	case WM831X_FLL_CONTROL_5:
		return true;
	default:
		return false;
	}
}
}


	return 0;
static bool wm831x_reg_volatile(struct device *dev, unsigned int reg)
{
	switch (reg) {
	case WM831X_SYSTEM_STATUS:
	case WM831X_ON_SOURCE:
	case WM831X_OFF_SOURCE:
	case WM831X_GPIO_LEVEL:
	case WM831X_SYSTEM_INTERRUPTS:
	case WM831X_INTERRUPT_STATUS_1:
	case WM831X_INTERRUPT_STATUS_2:
	case WM831X_INTERRUPT_STATUS_3:
	case WM831X_INTERRUPT_STATUS_4:
	case WM831X_INTERRUPT_STATUS_5:
	case WM831X_RTC_TIME_1:
	case WM831X_RTC_TIME_2:
	case WM831X_TOUCH_DATA_X:
	case WM831X_TOUCH_DATA_Y:
	case WM831X_TOUCH_DATA_Z:
	case WM831X_AUXADC_DATA:
	case WM831X_CHARGER_STATUS:
	case WM831X_DCDC_STATUS:
	case WM831X_LDO_STATUS:
	case WM831X_DCDC_UV_STATUS:
	case WM831X_LDO_UV_STATUS:
		return true;
	default:
		return false;
	}
}
}


/**
/**
@@ -191,14 +515,10 @@ static int wm831x_read(struct wm831x *wm831x, unsigned short reg,
 */
 */
int wm831x_reg_read(struct wm831x *wm831x, unsigned short reg)
int wm831x_reg_read(struct wm831x *wm831x, unsigned short reg)
{
{
	unsigned short val;
	unsigned int val;
	int ret;
	int ret;


	mutex_lock(&wm831x->io_lock);
	ret = regmap_read(wm831x->regmap, reg, &val);

	ret = wm831x_read(wm831x, reg, 2, &val);

	mutex_unlock(&wm831x->io_lock);


	if (ret < 0)
	if (ret < 0)
		return ret;
		return ret;
@@ -218,15 +538,7 @@ EXPORT_SYMBOL_GPL(wm831x_reg_read);
int wm831x_bulk_read(struct wm831x *wm831x, unsigned short reg,
int wm831x_bulk_read(struct wm831x *wm831x, unsigned short reg,
		     int count, u16 *buf)
		     int count, u16 *buf)
{
{
	int ret;
	return regmap_bulk_read(wm831x->regmap, reg, buf, count);

	mutex_lock(&wm831x->io_lock);

	ret = wm831x_read(wm831x, reg, count * 2, buf);

	mutex_unlock(&wm831x->io_lock);

	return ret;
}
}
EXPORT_SYMBOL_GPL(wm831x_bulk_read);
EXPORT_SYMBOL_GPL(wm831x_bulk_read);


@@ -234,7 +546,7 @@ static int wm831x_write(struct wm831x *wm831x, unsigned short reg,
			int bytes, void *src)
			int bytes, void *src)
{
{
	u16 *buf = src;
	u16 *buf = src;
	int i;
	int i, ret;


	BUG_ON(bytes % 2);
	BUG_ON(bytes % 2);
	BUG_ON(bytes <= 0);
	BUG_ON(bytes <= 0);
@@ -245,11 +557,10 @@ static int wm831x_write(struct wm831x *wm831x, unsigned short reg,


		dev_vdbg(wm831x->dev, "Write %04x to R%d(0x%x)\n",
		dev_vdbg(wm831x->dev, "Write %04x to R%d(0x%x)\n",
			 buf[i], reg + i, reg + i);
			 buf[i], reg + i, reg + i);

		ret = regmap_write(wm831x->regmap, reg + i, buf[i]);
		buf[i] = cpu_to_be16(buf[i]);
	}
	}


	return wm831x->write_dev(wm831x, reg, bytes, src);
	return 0;
}
}


/**
/**
@@ -286,20 +597,14 @@ int wm831x_set_bits(struct wm831x *wm831x, unsigned short reg,
		    unsigned short mask, unsigned short val)
		    unsigned short mask, unsigned short val)
{
{
	int ret;
	int ret;
	u16 r;


	mutex_lock(&wm831x->io_lock);
	mutex_lock(&wm831x->io_lock);


	ret = wm831x_read(wm831x, reg, 2, &r);
	if (!wm831x_reg_locked(wm831x, reg))
	if (ret < 0)
		ret = regmap_update_bits(wm831x->regmap, reg, mask, val);
		goto out;
	else

		ret = -EPERM;
	r &= ~mask;
	r |= val & mask;

	ret = wm831x_write(wm831x, reg, 2, &r);


out:
	mutex_unlock(&wm831x->io_lock);
	mutex_unlock(&wm831x->io_lock);


	return ret;
	return ret;
@@ -1292,6 +1597,17 @@ static struct mfd_cell backlight_devs[] = {
	},
	},
};
};


struct regmap_config wm831x_regmap_config = {
	.reg_bits = 16,
	.val_bits = 16,

	.max_register = WM831X_DBE_CHECK_DATA,
	.readable_reg = wm831x_reg_readable,
	.writeable_reg = wm831x_reg_writeable,
	.volatile_reg = wm831x_reg_volatile,
};
EXPORT_SYMBOL_GPL(wm831x_regmap_config);

/*
/*
 * Instantiate the generic non-control parts of the device.
 * Instantiate the generic non-control parts of the device.
 */
 */
@@ -1309,7 +1625,7 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
	ret = wm831x_reg_read(wm831x, WM831X_PARENT_ID);
	ret = wm831x_reg_read(wm831x, WM831X_PARENT_ID);
	if (ret < 0) {
	if (ret < 0) {
		dev_err(wm831x->dev, "Failed to read parent ID: %d\n", ret);
		dev_err(wm831x->dev, "Failed to read parent ID: %d\n", ret);
		goto err;
		goto err_regmap;
	}
	}
	switch (ret) {
	switch (ret) {
	case 0x6204:
	case 0x6204:
@@ -1318,20 +1634,20 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
	default:
	default:
		dev_err(wm831x->dev, "Device is not a WM831x: ID %x\n", ret);
		dev_err(wm831x->dev, "Device is not a WM831x: ID %x\n", ret);
		ret = -EINVAL;
		ret = -EINVAL;
		goto err;
		goto err_regmap;
	}
	}


	ret = wm831x_reg_read(wm831x, WM831X_REVISION);
	ret = wm831x_reg_read(wm831x, WM831X_REVISION);
	if (ret < 0) {
	if (ret < 0) {
		dev_err(wm831x->dev, "Failed to read revision: %d\n", ret);
		dev_err(wm831x->dev, "Failed to read revision: %d\n", ret);
		goto err;
		goto err_regmap;
	}
	}
	rev = (ret & WM831X_PARENT_REV_MASK) >> WM831X_PARENT_REV_SHIFT;
	rev = (ret & WM831X_PARENT_REV_MASK) >> WM831X_PARENT_REV_SHIFT;


	ret = wm831x_reg_read(wm831x, WM831X_RESET_ID);
	ret = wm831x_reg_read(wm831x, WM831X_RESET_ID);
	if (ret < 0) {
	if (ret < 0) {
		dev_err(wm831x->dev, "Failed to read device ID: %d\n", ret);
		dev_err(wm831x->dev, "Failed to read device ID: %d\n", ret);
		goto err;
		goto err_regmap;
	}
	}


	/* Some engineering samples do not have the ID set, rely on
	/* Some engineering samples do not have the ID set, rely on
@@ -1406,7 +1722,7 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
	default:
	default:
		dev_err(wm831x->dev, "Unknown WM831x device %04x\n", ret);
		dev_err(wm831x->dev, "Unknown WM831x device %04x\n", ret);
		ret = -EINVAL;
		ret = -EINVAL;
		goto err;
		goto err_regmap;
	}
	}


	/* This will need revisiting in future but is OK for all
	/* This will need revisiting in future but is OK for all
@@ -1420,7 +1736,7 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
	ret = wm831x_reg_read(wm831x, WM831X_SECURITY_KEY);
	ret = wm831x_reg_read(wm831x, WM831X_SECURITY_KEY);
	if (ret < 0) {
	if (ret < 0) {
		dev_err(wm831x->dev, "Failed to read security key: %d\n", ret);
		dev_err(wm831x->dev, "Failed to read security key: %d\n", ret);
		goto err;
		goto err_regmap;
	}
	}
	if (ret != 0) {
	if (ret != 0) {
		dev_warn(wm831x->dev, "Security key had non-zero value %x\n",
		dev_warn(wm831x->dev, "Security key had non-zero value %x\n",
@@ -1433,7 +1749,7 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
		ret = pdata->pre_init(wm831x);
		ret = pdata->pre_init(wm831x);
		if (ret != 0) {
		if (ret != 0) {
			dev_err(wm831x->dev, "pre_init() failed: %d\n", ret);
			dev_err(wm831x->dev, "pre_init() failed: %d\n", ret);
			goto err;
			goto err_regmap;
		}
		}
	}
	}


@@ -1456,7 +1772,7 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)


	ret = wm831x_irq_init(wm831x, irq);
	ret = wm831x_irq_init(wm831x, irq);
	if (ret != 0)
	if (ret != 0)
		goto err;
		goto err_regmap;


	wm831x_auxadc_init(wm831x);
	wm831x_auxadc_init(wm831x);


@@ -1552,8 +1868,9 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)


err_irq:
err_irq:
	wm831x_irq_exit(wm831x);
	wm831x_irq_exit(wm831x);
err:
err_regmap:
	mfd_remove_devices(wm831x->dev);
	mfd_remove_devices(wm831x->dev);
	regmap_exit(wm831x->regmap);
	kfree(wm831x);
	kfree(wm831x);
	return ret;
	return ret;
}
}
@@ -1565,6 +1882,7 @@ void wm831x_device_exit(struct wm831x *wm831x)
	if (wm831x->irq_base)
	if (wm831x->irq_base)
		free_irq(wm831x->irq_base + WM831X_IRQ_AUXADC_DATA, wm831x);
		free_irq(wm831x->irq_base + WM831X_IRQ_AUXADC_DATA, wm831x);
	wm831x_irq_exit(wm831x);
	wm831x_irq_exit(wm831x);
	regmap_exit(wm831x->regmap);
	kfree(wm831x);
	kfree(wm831x);
}
}


+12 −56
Original line number Original line Diff line number Diff line
@@ -18,67 +18,17 @@
#include <linux/delay.h>
#include <linux/delay.h>
#include <linux/mfd/core.h>
#include <linux/mfd/core.h>
#include <linux/slab.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/regmap.h>


#include <linux/mfd/wm831x/core.h>
#include <linux/mfd/wm831x/core.h>
#include <linux/mfd/wm831x/pdata.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;
	struct i2c_msg xfer[2];
	int ret;

	reg = cpu_to_be16(reg);

	xfer[0].addr = i2c->addr;
	xfer[0].flags = 0;
	xfer[0].len = 2;
	xfer[0].buf = (char *)&reg;

	xfer[1].addr = i2c->addr;
	xfer[1].flags = I2C_M_NOSTART;
	xfer[1].len = bytes;
	xfer[1].buf = (char *)src;

	ret = i2c_transfer(i2c->adapter, xfer, 2);
	if (ret < 0)
		return ret;
	if (ret != 2)
		return -EIO;

	return 0;
}

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


	wm831x = kzalloc(sizeof(struct wm831x), GFP_KERNEL);
	wm831x = kzalloc(sizeof(struct wm831x), GFP_KERNEL);
	if (wm831x == NULL)
	if (wm831x == NULL)
@@ -86,9 +36,15 @@ static int wm831x_i2c_probe(struct i2c_client *i2c,


	i2c_set_clientdata(i2c, wm831x);
	i2c_set_clientdata(i2c, wm831x);
	wm831x->dev = &i2c->dev;
	wm831x->dev = &i2c->dev;
	wm831x->control_data = i2c;

	wm831x->read_dev = wm831x_i2c_read_device;
	wm831x->regmap = regmap_init_i2c(i2c, &wm831x_regmap_config);
	wm831x->write_dev = wm831x_i2c_write_device;
	if (IS_ERR(wm831x->regmap)) {
		ret = PTR_ERR(wm831x->regmap);
		dev_err(wm831x->dev, "Failed to allocate register map: %d\n",
			ret);
		kfree(wm831x);
		return ret;
	}


	return wm831x_device_init(wm831x, id->driver_data, i2c->irq);
	return wm831x_device_init(wm831x, id->driver_data, i2c->irq);
}
}
+30 −166
Original line number Original line Diff line number Diff line
@@ -16,78 +16,19 @@
#include <linux/module.h>
#include <linux/module.h>
#include <linux/pm.h>
#include <linux/pm.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi.h>
#include <linux/regmap.h>
#include <linux/err.h>


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


static int wm831x_spi_read_device(struct wm831x *wm831x, unsigned short reg,
				  int bytes, void *dest)
{
	u16 tx_val;
	u16 *d = dest;
	int r, ret;

	/* Go register at a time */
	for (r = reg; r < reg + (bytes / 2); r++) {
		tx_val = r | 0x8000;

		ret = spi_write_then_read(wm831x->control_data,
					  (u8 *)&tx_val, 2, (u8 *)d, 2);
		if (ret != 0)
			return ret;

		*d = be16_to_cpu(*d);

		d++;
	}

	return 0;
}

static int wm831x_spi_write_device(struct wm831x *wm831x, unsigned short reg,
				   int bytes, void *src)
{
	struct spi_device *spi = wm831x->control_data;
	u16 *s = src;
	u16 data[2];
	int ret, r;

	/* Go register at a time */
	for (r = reg; r < reg + (bytes / 2); r++) {
		data[0] = r;
		data[1] = *s++;

		ret = spi_write(spi, (char *)&data, sizeof(data));
		if (ret != 0)
			return ret;
	}

	return 0;
}

static int __devinit wm831x_spi_probe(struct spi_device *spi)
static int __devinit wm831x_spi_probe(struct spi_device *spi)
{
{
	const struct spi_device_id *id = spi_get_device_id(spi);
	struct wm831x *wm831x;
	struct wm831x *wm831x;
	enum wm831x_parent type;
	enum wm831x_parent type;
	int ret;


	/* Currently SPI support for ID tables is unmerged, we're faking it */
	type = (enum wm831x_parent)id->driver_data;
	if (strcmp(spi->modalias, "wm8310") == 0)
		type = WM8310;
	else if (strcmp(spi->modalias, "wm8311") == 0)
		type = WM8311;
	else if (strcmp(spi->modalias, "wm8312") == 0)
		type = WM8312;
	else if (strcmp(spi->modalias, "wm8320") == 0)
		type = WM8320;
	else if (strcmp(spi->modalias, "wm8321") == 0)
		type = WM8321;
	else if (strcmp(spi->modalias, "wm8325") == 0)
		type = WM8325;
	else if (strcmp(spi->modalias, "wm8326") == 0)
		type = WM8326;
	else {
		dev_err(&spi->dev, "Unknown device type\n");
		return -EINVAL;
	}


	wm831x = kzalloc(sizeof(struct wm831x), GFP_KERNEL);
	wm831x = kzalloc(sizeof(struct wm831x), GFP_KERNEL);
	if (wm831x == NULL)
	if (wm831x == NULL)
@@ -98,9 +39,15 @@ static int __devinit wm831x_spi_probe(struct spi_device *spi)


	dev_set_drvdata(&spi->dev, wm831x);
	dev_set_drvdata(&spi->dev, wm831x);
	wm831x->dev = &spi->dev;
	wm831x->dev = &spi->dev;
	wm831x->control_data = spi;

	wm831x->read_dev = wm831x_spi_read_device;
	wm831x->regmap = regmap_init_spi(spi, &wm831x_regmap_config);
	wm831x->write_dev = wm831x_spi_write_device;
	if (IS_ERR(wm831x->regmap)) {
		ret = PTR_ERR(wm831x->regmap);
		dev_err(wm831x->dev, "Failed to allocate register map: %d\n",
			ret);
		kfree(wm831x);
		return ret;
	}


	return wm831x_device_init(wm831x, type, spi->irq);
	return wm831x_device_init(wm831x, type, spi->irq);
}
}
@@ -126,79 +73,26 @@ static const struct dev_pm_ops wm831x_spi_pm = {
	.suspend = wm831x_spi_suspend,
	.suspend = wm831x_spi_suspend,
};
};


static struct spi_driver wm8310_spi_driver = {
static const struct spi_device_id wm831x_spi_ids[] = {
	.driver = {
	{ "wm8310", WM8310 },
		.name	= "wm8310",
	{ "wm8311", WM8311 },
		.bus	= &spi_bus_type,
	{ "wm8312", WM8312 },
		.owner	= THIS_MODULE,
	{ "wm8320", WM8320 },
		.pm	= &wm831x_spi_pm,
	{ "wm8321", WM8321 },
	},
	{ "wm8325", WM8325 },
	.probe		= wm831x_spi_probe,
	{ "wm8326", WM8326 },
	.remove		= __devexit_p(wm831x_spi_remove),
	{ },
};
};
MODULE_DEVICE_TABLE(spi, wm831x_spi_id);


static struct spi_driver wm8311_spi_driver = {
static struct spi_driver wm831x_spi_driver = {
	.driver = {
	.driver = {
		.name	= "wm8311",
		.name	= "wm831x",
		.bus	= &spi_bus_type,
		.owner	= THIS_MODULE,
		.pm	= &wm831x_spi_pm,
	},
	.probe		= wm831x_spi_probe,
	.remove		= __devexit_p(wm831x_spi_remove),
};

static struct spi_driver wm8312_spi_driver = {
	.driver = {
		.name	= "wm8312",
		.bus	= &spi_bus_type,
		.owner	= THIS_MODULE,
		.pm	= &wm831x_spi_pm,
	},
	.probe		= wm831x_spi_probe,
	.remove		= __devexit_p(wm831x_spi_remove),
};

static struct spi_driver wm8320_spi_driver = {
	.driver = {
		.name	= "wm8320",
		.bus	= &spi_bus_type,
		.owner	= THIS_MODULE,
		.pm	= &wm831x_spi_pm,
	},
	.probe		= wm831x_spi_probe,
	.remove		= __devexit_p(wm831x_spi_remove),
};

static struct spi_driver wm8321_spi_driver = {
	.driver = {
		.name	= "wm8321",
		.bus	= &spi_bus_type,
		.owner	= THIS_MODULE,
		.pm	= &wm831x_spi_pm,
	},
	.probe		= wm831x_spi_probe,
	.remove		= __devexit_p(wm831x_spi_remove),
};

static struct spi_driver wm8325_spi_driver = {
	.driver = {
		.name	= "wm8325",
		.bus	= &spi_bus_type,
		.owner	= THIS_MODULE,
		.pm	= &wm831x_spi_pm,
	},
	.probe		= wm831x_spi_probe,
	.remove		= __devexit_p(wm831x_spi_remove),
};

static struct spi_driver wm8326_spi_driver = {
	.driver = {
		.name	= "wm8326",
		.bus	= &spi_bus_type,
		.bus	= &spi_bus_type,
		.owner	= THIS_MODULE,
		.owner	= THIS_MODULE,
		.pm	= &wm831x_spi_pm,
		.pm	= &wm831x_spi_pm,
	},
	},
	.id_table	= wm831x_spi_ids,
	.probe		= wm831x_spi_probe,
	.probe		= wm831x_spi_probe,
	.remove		= __devexit_p(wm831x_spi_remove),
	.remove		= __devexit_p(wm831x_spi_remove),
};
};
@@ -207,33 +101,9 @@ static int __init wm831x_spi_init(void)
{
{
	int ret;
	int ret;


	ret = spi_register_driver(&wm8310_spi_driver);
	ret = spi_register_driver(&wm831x_spi_driver);
	if (ret != 0)
		pr_err("Failed to register WM8310 SPI driver: %d\n", ret);

	ret = spi_register_driver(&wm8311_spi_driver);
	if (ret != 0)
		pr_err("Failed to register WM8311 SPI driver: %d\n", ret);

	ret = spi_register_driver(&wm8312_spi_driver);
	if (ret != 0)
		pr_err("Failed to register WM8312 SPI driver: %d\n", ret);

	ret = spi_register_driver(&wm8320_spi_driver);
	if (ret != 0)
		pr_err("Failed to register WM8320 SPI driver: %d\n", ret);

	ret = spi_register_driver(&wm8321_spi_driver);
	if (ret != 0)
		pr_err("Failed to register WM8321 SPI driver: %d\n", ret);

	ret = spi_register_driver(&wm8325_spi_driver);
	if (ret != 0)
		pr_err("Failed to register WM8325 SPI driver: %d\n", ret);

	ret = spi_register_driver(&wm8326_spi_driver);
	if (ret != 0)
	if (ret != 0)
		pr_err("Failed to register WM8326 SPI driver: %d\n", ret);
		pr_err("Failed to register WM831x SPI driver: %d\n", ret);


	return 0;
	return 0;
}
}
@@ -241,13 +111,7 @@ subsys_initcall(wm831x_spi_init);


static void __exit wm831x_spi_exit(void)
static void __exit wm831x_spi_exit(void)
{
{
	spi_unregister_driver(&wm8326_spi_driver);
	spi_unregister_driver(&wm831x_spi_driver);
	spi_unregister_driver(&wm8325_spi_driver);
	spi_unregister_driver(&wm8321_spi_driver);
	spi_unregister_driver(&wm8320_spi_driver);
	spi_unregister_driver(&wm8312_spi_driver);
	spi_unregister_driver(&wm8311_spi_driver);
	spi_unregister_driver(&wm8310_spi_driver);
}
}
module_exit(wm831x_spi_exit);
module_exit(wm831x_spi_exit);


+29 −77

File changed.

Preview size limit exceeded, changes collapsed.

Loading