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

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

ASoC: wm2000: Add regulator support

parent 8fed54ae
Loading
Loading
Loading
Loading
+47 −6
Original line number Original line Diff line number Diff line
@@ -31,6 +31,7 @@
#include <linux/i2c.h>
#include <linux/i2c.h>
#include <linux/regmap.h>
#include <linux/regmap.h>
#include <linux/debugfs.h>
#include <linux/debugfs.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm.h>
@@ -43,6 +44,14 @@


#include "wm2000.h"
#include "wm2000.h"


#define WM2000_NUM_SUPPLIES 3

static const char *wm2000_supplies[WM2000_NUM_SUPPLIES] = {
	"SPKVDD",
	"DBVDD",
	"DCVDD",
};

enum wm2000_anc_mode {
enum wm2000_anc_mode {
	ANC_ACTIVE = 0,
	ANC_ACTIVE = 0,
	ANC_BYPASS = 1,
	ANC_BYPASS = 1,
@@ -54,6 +63,8 @@ struct wm2000_priv {
	struct i2c_client *i2c;
	struct i2c_client *i2c;
	struct regmap *regmap;
	struct regmap *regmap;


	struct regulator_bulk_data supplies[WM2000_NUM_SUPPLIES];

	enum wm2000_anc_mode anc_mode;
	enum wm2000_anc_mode anc_mode;


	unsigned int anc_active:1;
	unsigned int anc_active:1;
@@ -126,6 +137,12 @@ static int wm2000_power_up(struct i2c_client *i2c, int analogue)


	dev_dbg(&i2c->dev, "Beginning power up\n");
	dev_dbg(&i2c->dev, "Beginning power up\n");


	ret = regulator_bulk_enable(WM2000_NUM_SUPPLIES, wm2000->supplies);
	if (ret != 0) {
		dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret);
		return ret;
	}

	if (!wm2000->mclk_div) {
	if (!wm2000->mclk_div) {
		dev_dbg(&i2c->dev, "Disabling MCLK divider\n");
		dev_dbg(&i2c->dev, "Disabling MCLK divider\n");
		wm2000_write(i2c, WM2000_REG_SYS_CTL2,
		wm2000_write(i2c, WM2000_REG_SYS_CTL2,
@@ -143,12 +160,14 @@ static int wm2000_power_up(struct i2c_client *i2c, int analogue)
	if (!wm2000_poll_bit(i2c, WM2000_REG_ANC_STAT,
	if (!wm2000_poll_bit(i2c, WM2000_REG_ANC_STAT,
			     WM2000_ANC_ENG_IDLE)) {
			     WM2000_ANC_ENG_IDLE)) {
		dev_err(&i2c->dev, "ANC engine failed to reset\n");
		dev_err(&i2c->dev, "ANC engine failed to reset\n");
		regulator_bulk_disable(WM2000_NUM_SUPPLIES, wm2000->supplies);
		return -ETIMEDOUT;
		return -ETIMEDOUT;
	}
	}


	if (!wm2000_poll_bit(i2c, WM2000_REG_SYS_STATUS,
	if (!wm2000_poll_bit(i2c, WM2000_REG_SYS_STATUS,
			     WM2000_STATUS_BOOT_COMPLETE)) {
			     WM2000_STATUS_BOOT_COMPLETE)) {
		dev_err(&i2c->dev, "ANC engine failed to initialise\n");
		dev_err(&i2c->dev, "ANC engine failed to initialise\n");
		regulator_bulk_disable(WM2000_NUM_SUPPLIES, wm2000->supplies);
		return -ETIMEDOUT;
		return -ETIMEDOUT;
	}
	}


@@ -163,11 +182,13 @@ static int wm2000_power_up(struct i2c_client *i2c, int analogue)
			      wm2000->anc_download_size);
			      wm2000->anc_download_size);
	if (ret < 0) {
	if (ret < 0) {
		dev_err(&i2c->dev, "i2c_transfer() failed: %d\n", ret);
		dev_err(&i2c->dev, "i2c_transfer() failed: %d\n", ret);
		regulator_bulk_disable(WM2000_NUM_SUPPLIES, wm2000->supplies);
		return ret;
		return ret;
	}
	}
	if (ret != wm2000->anc_download_size) {
	if (ret != wm2000->anc_download_size) {
		dev_err(&i2c->dev, "i2c_transfer() failed, %d != %d\n",
		dev_err(&i2c->dev, "i2c_transfer() failed, %d != %d\n",
			ret, wm2000->anc_download_size);
			ret, wm2000->anc_download_size);
		regulator_bulk_disable(WM2000_NUM_SUPPLIES, wm2000->supplies);
		return -EIO;
		return -EIO;
	}
	}


@@ -201,6 +222,7 @@ static int wm2000_power_up(struct i2c_client *i2c, int analogue)
	if (!wm2000_poll_bit(i2c, WM2000_REG_SYS_STATUS,
	if (!wm2000_poll_bit(i2c, WM2000_REG_SYS_STATUS,
			     WM2000_STATUS_MOUSE_ACTIVE)) {
			     WM2000_STATUS_MOUSE_ACTIVE)) {
		dev_err(&i2c->dev, "Timed out waiting for device\n");
		dev_err(&i2c->dev, "Timed out waiting for device\n");
		regulator_bulk_disable(WM2000_NUM_SUPPLIES, wm2000->supplies);
		return -ETIMEDOUT;
		return -ETIMEDOUT;
	}
	}


@@ -238,6 +260,8 @@ static int wm2000_power_down(struct i2c_client *i2c, int analogue)
		return -ETIMEDOUT;
		return -ETIMEDOUT;
	}
	}


	regulator_bulk_disable(WM2000_NUM_SUPPLIES, wm2000->supplies);

	dev_dbg(&i2c->dev, "powered off\n");
	dev_dbg(&i2c->dev, "powered off\n");
	wm2000->anc_mode = ANC_OFF;
	wm2000->anc_mode = ANC_OFF;


@@ -747,7 +771,7 @@ static int __devinit wm2000_i2c_probe(struct i2c_client *i2c,
	struct wm2000_platform_data *pdata;
	struct wm2000_platform_data *pdata;
	const char *filename;
	const char *filename;
	const struct firmware *fw = NULL;
	const struct firmware *fw = NULL;
	int ret;
	int ret, i;
	int reg;
	int reg;
	u16 id;
	u16 id;


@@ -768,6 +792,22 @@ static int __devinit wm2000_i2c_probe(struct i2c_client *i2c,
		goto out;
		goto out;
	}
	}


	for (i = 0; i < WM2000_NUM_SUPPLIES; i++)
		wm2000->supplies[i].supply = wm2000_supplies[i];

	ret = devm_regulator_bulk_get(&i2c->dev, WM2000_NUM_SUPPLIES,
				      wm2000->supplies);
	if (ret != 0) {
		dev_err(&i2c->dev, "Failed to get supplies: %d\n", ret);
		return ret;
	}

	ret = regulator_bulk_enable(WM2000_NUM_SUPPLIES, wm2000->supplies);
	if (ret != 0) {
		dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret);
		return ret;
	}

	/* Verify that this is a WM2000 */
	/* Verify that this is a WM2000 */
	reg = wm2000_read(i2c, WM2000_REG_ID1);
	reg = wm2000_read(i2c, WM2000_REG_ID1);
	id = reg << 8;
	id = reg << 8;
@@ -777,7 +817,7 @@ static int __devinit wm2000_i2c_probe(struct i2c_client *i2c,
	if (id != 0x2000) {
	if (id != 0x2000) {
		dev_err(&i2c->dev, "Device is not a WM2000 - ID %x\n", id);
		dev_err(&i2c->dev, "Device is not a WM2000 - ID %x\n", id);
		ret = -ENODEV;
		ret = -ENODEV;
		goto out;
		goto err_supplies;
	}
	}


	reg = wm2000_read(i2c, WM2000_REG_REVISON);
	reg = wm2000_read(i2c, WM2000_REG_REVISON);
@@ -796,7 +836,7 @@ static int __devinit wm2000_i2c_probe(struct i2c_client *i2c,
	ret = request_firmware(&fw, filename, &i2c->dev);
	ret = request_firmware(&fw, filename, &i2c->dev);
	if (ret != 0) {
	if (ret != 0) {
		dev_err(&i2c->dev, "Failed to acquire ANC data: %d\n", ret);
		dev_err(&i2c->dev, "Failed to acquire ANC data: %d\n", ret);
		goto out;
		goto err_supplies;
	}
	}


	/* Pre-cook the concatenation of the register address onto the image */
	/* Pre-cook the concatenation of the register address onto the image */
@@ -807,7 +847,7 @@ static int __devinit wm2000_i2c_probe(struct i2c_client *i2c,
	if (wm2000->anc_download == NULL) {
	if (wm2000->anc_download == NULL) {
		dev_err(&i2c->dev, "Out of memory\n");
		dev_err(&i2c->dev, "Out of memory\n");
		ret = -ENOMEM;
		ret = -ENOMEM;
		goto out;
		goto err_supplies;
	}
	}


	wm2000->anc_download[0] = 0x80;
	wm2000->anc_download[0] = 0x80;
@@ -822,8 +862,9 @@ static int __devinit wm2000_i2c_probe(struct i2c_client *i2c,
	wm2000_reset(wm2000);
	wm2000_reset(wm2000);


	ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm2000, NULL, 0);
	ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm2000, NULL, 0);
	if (!ret)

		goto out;
err_supplies:
	regulator_bulk_disable(WM2000_NUM_SUPPLIES, wm2000->supplies);


out:
out:
	release_firmware(fw);
	release_firmware(fw);