Commit 0fd0ba5f authored by Takashi Iwai's avatar Takashi Iwai

Merge tag 'asoc-3.7' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into for-next

ASoC: Additional updates for v3.7

A couple more updates for 3.7, enhancements to the ux500 and wm2000
drivers, a new driver for DA9055 and the support for regulator bypass
mode.  With the exception of the DA9055 this has all had a chance to
soak in -next (the driver was added on Friday so should be in -next
today).
parents b7ef37d0 9911f7f7
...@@ -349,3 +349,24 @@ Description: ...@@ -349,3 +349,24 @@ Description:
This will be one of the same strings reported by This will be one of the same strings reported by
the "state" attribute. the "state" attribute.
What: /sys/class/regulator/.../bypass
Date: September 2012
KernelVersion: 3.7
Contact: Mark Brown <broonie@opensource.wolfsonmicro.com>
Description:
Some regulator directories will contain a field called
bypass. This indicates if the device is in bypass mode.
This will be one of the following strings:
'enabled'
'disabled'
'unknown'
'enabled' means the regulator is in bypass mode.
'disabled' means that the regulator is regulating.
'unknown' means software cannot determine the state, or
the reported state is invalid.
Cirrus Logic CS4271 DT bindings
This driver supports both the I2C and the SPI bus.
Required properties:
- compatible: "cirrus,cs4271"
For required properties on SPI, please consult
Documentation/devicetree/bindings/spi/spi-bus.txt
Required properties on I2C:
- reg: the i2c address
Optional properties:
- reset-gpio: a GPIO spec to define which pin is connected to the chip's
!RESET pin
Examples:
codec_i2c: cs4271@10 {
compatible = "cirrus,cs4271";
reg = <0x10>;
reset-gpio = <&gpio 23 0>;
};
codec_spi: cs4271@0 {
compatible = "cirrus,cs4271";
reg = <0x0>;
reset-gpio = <&gpio 23 0>;
spi-max-frequency = <6000000>;
};
* MOP500 Audio Machine Driver
This node is responsible for linking together all ux500 Audio Driver components.
Required properties:
- compatible : "stericsson,snd-soc-mop500"
Non-standard properties:
- stericsson,cpu-dai : Phandle to the CPU-side DAI
- stericsson,audio-codec : Phandle to the Audio CODEC
- stericsson,card-name : Over-ride default card name
Example:
sound {
compatible = "stericsson,snd-soc-mop500";
stericsson,cpu-dai = <&msp1 &msp3>;
stericsson,audio-codec = <&codec>;
};
msp1: msp@80124000 {
compatible = "stericsson,ux500-msp-i2s";
reg = <0x80124000 0x1000>;
interrupts = <0 62 0x4>;
v-ape-supply = <&db8500_vape_reg>;
};
msp3: msp@80125000 {
compatible = "stericsson,ux500-msp-i2s";
reg = <0x80125000 0x1000>;
interrupts = <0 62 0x4>;
v-ape-supply = <&db8500_vape_reg>;
};
codec: ab8500-codec {
compatible = "stericsson,ab8500-codec";
stericsson,earpeice-cmv = <950>; /* Units in mV. */
};
* ux500 MSP (CPU-side Digital Audio Interface)
Required properties:
- compatible :"stericsson,ux500-msp-i2s"
- reg : Physical base address and length of the device's registers.
Optional properties:
- interrupts : The interrupt output from the device.
- interrupt-parent : The parent interrupt controller.
- <name>-supply : Phandle to the regulator <name> supply
Example:
sound {
compatible = "stericsson,snd-soc-mop500";
stericsson,platform-pcm-dma = <&pcm>;
stericsson,cpu-dai = <&msp1 &msp3>;
stericsson,audio-codec = <&codec>;
};
pcm: ux500-pcm {
compatible = "stericsson,ux500-pcm";
};
msp1: msp@80124000 {
compatible = "stericsson,ux500-msp-i2s";
reg = <0x80124000 0x1000>;
interrupts = <0 62 0x4>;
v-ape-supply = <&db8500_vape_reg>;
};
msp3: msp@80125000 {
compatible = "stericsson,ux500-msp-i2s";
reg = <0x80125000 0x1000>;
interrupts = <0 62 0x4>;
v-ape-supply = <&db8500_vape_reg>;
};
codec: ab8500-codec {
compatible = "stericsson,ab8500-codec";
stericsson,earpeice-cmv = <950>; /* Units in mV. */
};
...@@ -348,4 +348,5 @@ void __init eukrea_mbimx27_baseboard_init(void) ...@@ -348,4 +348,5 @@ void __init eukrea_mbimx27_baseboard_init(void)
imx27_add_imx_keypad(&eukrea_mbimx27_keymap_data); imx27_add_imx_keypad(&eukrea_mbimx27_keymap_data);
gpio_led_register_device(-1, &eukrea_mbimx27_gpio_led_info); gpio_led_register_device(-1, &eukrea_mbimx27_gpio_led_info);
imx_add_platform_device("eukrea_tlv320", 0, NULL, 0, NULL, 0);
} }
...@@ -306,4 +306,5 @@ void __init eukrea_mbimxsd25_baseboard_init(void) ...@@ -306,4 +306,5 @@ void __init eukrea_mbimxsd25_baseboard_init(void)
platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices)); platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
gpio_led_register_device(-1, &eukrea_mbimxsd_led_info); gpio_led_register_device(-1, &eukrea_mbimxsd_led_info);
imx_add_gpio_keys(&eukrea_mbimxsd_button_data); imx_add_gpio_keys(&eukrea_mbimxsd_button_data);
imx_add_platform_device("eukrea_tlv320", 0, NULL, 0, NULL, 0);
} }
...@@ -315,4 +315,5 @@ void __init eukrea_mbimxsd35_baseboard_init(void) ...@@ -315,4 +315,5 @@ void __init eukrea_mbimxsd35_baseboard_init(void)
platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices)); platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
gpio_led_register_device(-1, &eukrea_mbimxsd_led_info); gpio_led_register_device(-1, &eukrea_mbimxsd_led_info);
imx_add_gpio_keys(&eukrea_mbimxsd_button_data); imx_add_gpio_keys(&eukrea_mbimxsd_button_data);
imx_add_platform_device("eukrea_tlv320", 0, NULL, 0, NULL, 0);
} }
...@@ -228,4 +228,5 @@ void __init eukrea_mbimxsd51_baseboard_init(void) ...@@ -228,4 +228,5 @@ void __init eukrea_mbimxsd51_baseboard_init(void)
gpio_led_register_device(-1, &eukrea_mbimxsd51_led_info); gpio_led_register_device(-1, &eukrea_mbimxsd51_led_info);
imx_add_gpio_keys(&eukrea_mbimxsd51_button_data); imx_add_gpio_keys(&eukrea_mbimxsd51_button_data);
imx_add_platform_device("eukrea_tlv320", 0, NULL, 0, NULL, 0);
} }
...@@ -7,7 +7,6 @@ ...@@ -7,7 +7,6 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/pinctrl/consumer.h>
#include <plat/gpio-nomadik.h> #include <plat/gpio-nomadik.h>
#include <plat/pincfg.h> #include <plat/pincfg.h>
...@@ -23,53 +22,6 @@ ...@@ -23,53 +22,6 @@
#include "devices-db8500.h" #include "devices-db8500.h"
#include "pins-db8500.h" #include "pins-db8500.h"
/* MSP1/3 Tx/Rx usage protection */
static DEFINE_SPINLOCK(msp_rxtx_lock);
/* Reference Count */
static int msp_rxtx_ref;
/* Pin modes */
struct pinctrl *msp1_p;
struct pinctrl_state *msp1_def;
struct pinctrl_state *msp1_sleep;
int msp13_i2s_init(void)
{
int retval = 0;
unsigned long flags;
spin_lock_irqsave(&msp_rxtx_lock, flags);
if (msp_rxtx_ref == 0 && !(IS_ERR(msp1_p) || IS_ERR(msp1_def))) {
retval = pinctrl_select_state(msp1_p, msp1_def);
if (retval)
pr_err("could not set MSP1 defstate\n");
}
if (!retval)
msp_rxtx_ref++;
spin_unlock_irqrestore(&msp_rxtx_lock, flags);
return retval;
}
int msp13_i2s_exit(void)
{
int retval = 0;
unsigned long flags;
spin_lock_irqsave(&msp_rxtx_lock, flags);
WARN_ON(!msp_rxtx_ref);
msp_rxtx_ref--;
if (msp_rxtx_ref == 0 && !(IS_ERR(msp1_p) || IS_ERR(msp1_sleep))) {
retval = pinctrl_select_state(msp1_p, msp1_sleep);
if (retval)
pr_err("could not set MSP1 sleepstate\n");
}
spin_unlock_irqrestore(&msp_rxtx_lock, flags);
return retval;
}
static struct stedma40_chan_cfg msp0_dma_rx = { static struct stedma40_chan_cfg msp0_dma_rx = {
.high_priority = true, .high_priority = true,
.dir = STEDMA40_PERIPH_TO_MEM, .dir = STEDMA40_PERIPH_TO_MEM,
...@@ -132,8 +84,6 @@ static struct msp_i2s_platform_data msp1_platform_data = { ...@@ -132,8 +84,6 @@ static struct msp_i2s_platform_data msp1_platform_data = {
.id = MSP_I2S_1, .id = MSP_I2S_1,
.msp_i2s_dma_rx = NULL, .msp_i2s_dma_rx = NULL,
.msp_i2s_dma_tx = &msp1_dma_tx, .msp_i2s_dma_tx = &msp1_dma_tx,
.msp_i2s_init = msp13_i2s_init,
.msp_i2s_exit = msp13_i2s_exit,
}; };
static struct stedma40_chan_cfg msp2_dma_rx = { static struct stedma40_chan_cfg msp2_dma_rx = {
...@@ -219,49 +169,22 @@ static struct msp_i2s_platform_data msp3_platform_data = { ...@@ -219,49 +169,22 @@ static struct msp_i2s_platform_data msp3_platform_data = {
.id = MSP_I2S_3, .id = MSP_I2S_3,
.msp_i2s_dma_rx = &msp1_dma_rx, .msp_i2s_dma_rx = &msp1_dma_rx,
.msp_i2s_dma_tx = NULL, .msp_i2s_dma_tx = NULL,
.msp_i2s_init = msp13_i2s_init,
.msp_i2s_exit = msp13_i2s_exit,
}; };
int mop500_msp_init(struct device *parent) int mop500_msp_init(struct device *parent)
{ {
struct platform_device *msp1;
pr_info("%s: Register platform-device 'snd-soc-mop500'.\n", __func__); pr_info("%s: Register platform-device 'snd-soc-mop500'.\n", __func__);
platform_device_register(&snd_soc_mop500); platform_device_register(&snd_soc_mop500);
pr_info("Initialize MSP I2S-devices.\n"); pr_info("Initialize MSP I2S-devices.\n");
db8500_add_msp_i2s(parent, 0, U8500_MSP0_BASE, IRQ_DB8500_MSP0, db8500_add_msp_i2s(parent, 0, U8500_MSP0_BASE, IRQ_DB8500_MSP0,
&msp0_platform_data); &msp0_platform_data);
msp1 = db8500_add_msp_i2s(parent, 1, U8500_MSP1_BASE, IRQ_DB8500_MSP1, db8500_add_msp_i2s(parent, 1, U8500_MSP1_BASE, IRQ_DB8500_MSP1,
&msp1_platform_data); &msp1_platform_data);
db8500_add_msp_i2s(parent, 2, U8500_MSP2_BASE, IRQ_DB8500_MSP2, db8500_add_msp_i2s(parent, 2, U8500_MSP2_BASE, IRQ_DB8500_MSP2,
&msp2_platform_data); &msp2_platform_data);
db8500_add_msp_i2s(parent, 3, U8500_MSP3_BASE, IRQ_DB8500_MSP1, db8500_add_msp_i2s(parent, 3, U8500_MSP3_BASE, IRQ_DB8500_MSP1,
&msp3_platform_data); &msp3_platform_data);
/* Get the pinctrl handle for MSP1 */
if (msp1) {
msp1_p = pinctrl_get(&msp1->dev);
if (IS_ERR(msp1_p))
dev_err(&msp1->dev, "could not get MSP1 pinctrl\n");
else {
msp1_def = pinctrl_lookup_state(msp1_p,
PINCTRL_STATE_DEFAULT);
if (IS_ERR(msp1_def)) {
dev_err(&msp1->dev,
"could not get MSP1 defstate\n");
}
msp1_sleep = pinctrl_lookup_state(msp1_p,
PINCTRL_STATE_SLEEP);
if (IS_ERR(msp1_sleep))
dev_err(&msp1->dev,
"could not get MSP1 idlestate\n");
}
}
pr_info("%s: Register platform-device 'ux500-pcm'\n", __func__);
platform_device_register(&ux500_pcm);
return 0; return 0;
} }
...@@ -22,8 +22,6 @@ struct msp_i2s_platform_data { ...@@ -22,8 +22,6 @@ struct msp_i2s_platform_data {
enum msp_i2s_id id; enum msp_i2s_id id;
struct stedma40_chan_cfg *msp_i2s_dma_rx; struct stedma40_chan_cfg *msp_i2s_dma_rx;
struct stedma40_chan_cfg *msp_i2s_dma_tx; struct stedma40_chan_cfg *msp_i2s_dma_tx;
int (*msp_i2s_init) (void);
int (*msp_i2s_exit) (void);
}; };
#endif #endif
...@@ -434,6 +434,11 @@ static int __devinit arizona_extcon_probe(struct platform_device *pdev) ...@@ -434,6 +434,11 @@ static int __devinit arizona_extcon_probe(struct platform_device *pdev)
regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE, regmap_update_bits(arizona->regmap, ARIZONA_JACK_DETECT_ANALOGUE,
ARIZONA_JD1_ENA, ARIZONA_JD1_ENA); ARIZONA_JD1_ENA, ARIZONA_JD1_ENA);
ret = regulator_allow_bypass(info->micvdd, true);
if (ret != 0)
dev_warn(arizona->dev, "Failed to set MICVDD to bypass: %d\n",
ret);
pm_runtime_put(&pdev->dev); pm_runtime_put(&pdev->dev);
return 0; return 0;
......
...@@ -39,6 +39,8 @@ static struct regulator_ops arizona_ldo1_ops = { ...@@ -39,6 +39,8 @@ static struct regulator_ops arizona_ldo1_ops = {
.map_voltage = regulator_map_voltage_linear, .map_voltage = regulator_map_voltage_linear,
.get_voltage_sel = regulator_get_voltage_sel_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_sel = regulator_set_voltage_sel_regmap, .set_voltage_sel = regulator_set_voltage_sel_regmap,
.get_bypass = regulator_get_bypass_regmap,
.set_bypass = regulator_set_bypass_regmap,
}; };
static const struct regulator_desc arizona_ldo1 = { static const struct regulator_desc arizona_ldo1 = {
...@@ -49,6 +51,8 @@ static const struct regulator_desc arizona_ldo1 = { ...@@ -49,6 +51,8 @@ static const struct regulator_desc arizona_ldo1 = {
.vsel_reg = ARIZONA_LDO1_CONTROL_1, .vsel_reg = ARIZONA_LDO1_CONTROL_1,
.vsel_mask = ARIZONA_LDO1_VSEL_MASK, .vsel_mask = ARIZONA_LDO1_VSEL_MASK,
.bypass_reg = ARIZONA_LDO1_CONTROL_1,
.bypass_mask = ARIZONA_LDO1_BYPASS,
.min_uV = 900000, .min_uV = 900000,
.uV_step = 50000, .uV_step = 50000,
.n_voltages = 7, .n_voltages = 7,
......
...@@ -82,6 +82,9 @@ static struct regulator_ops arizona_micsupp_ops = { ...@@ -82,6 +82,9 @@ static struct regulator_ops arizona_micsupp_ops = {
.get_voltage_sel = regulator_get_voltage_sel_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_sel = regulator_set_voltage_sel_regmap, .set_voltage_sel = regulator_set_voltage_sel_regmap,
.get_bypass = regulator_get_bypass_regmap,
.set_bypass = regulator_set_bypass_regmap,
}; };
static const struct regulator_desc arizona_micsupp = { static const struct regulator_desc arizona_micsupp = {
...@@ -95,6 +98,8 @@ static const struct regulator_desc arizona_micsupp = { ...@@ -95,6 +98,8 @@ static const struct regulator_desc arizona_micsupp = {
.vsel_mask = ARIZONA_LDO2_VSEL_MASK, .vsel_mask = ARIZONA_LDO2_VSEL_MASK,
.enable_reg = ARIZONA_MIC_CHARGE_PUMP_1, .enable_reg = ARIZONA_MIC_CHARGE_PUMP_1,
.enable_mask = ARIZONA_CPMIC_ENA, .enable_mask = ARIZONA_CPMIC_ENA,
.bypass_reg = ARIZONA_MIC_CHARGE_PUMP_1,
.bypass_mask = ARIZONA_CPMIC_BYPASS,
.owner = THIS_MODULE, .owner = THIS_MODULE,
}; };
......
...@@ -77,6 +77,7 @@ struct regulator { ...@@ -77,6 +77,7 @@ struct regulator {
struct device *dev; struct device *dev;
struct list_head list; struct list_head list;
unsigned int always_on:1; unsigned int always_on:1;
unsigned int bypass:1;
int uA_load; int uA_load;
int min_uV; int min_uV;
int max_uV; int max_uV;
...@@ -394,6 +395,9 @@ static ssize_t regulator_status_show(struct device *dev, ...@@ -394,6 +395,9 @@ static ssize_t regulator_status_show(struct device *dev,
case REGULATOR_STATUS_STANDBY: case REGULATOR_STATUS_STANDBY:
label = "standby"; label = "standby";
break; break;
case REGULATOR_STATUS_BYPASS:
label = "bypass";
break;
case REGULATOR_STATUS_UNDEFINED: case REGULATOR_STATUS_UNDEFINED:
label = "undefined"; label = "undefined";
break; break;
...@@ -585,6 +589,27 @@ static ssize_t regulator_suspend_standby_state_show(struct device *dev, ...@@ -585,6 +589,27 @@ static ssize_t regulator_suspend_standby_state_show(struct device *dev,
static DEVICE_ATTR(suspend_standby_state, 0444, static DEVICE_ATTR(suspend_standby_state, 0444,
regulator_suspend_standby_state_show, NULL); regulator_suspend_standby_state_show, NULL);
static ssize_t regulator_bypass_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct regulator_dev *rdev = dev_get_drvdata(dev);
const char *report;
bool bypass;
int ret;
ret = rdev->desc->ops->get_bypass(rdev, &bypass);
if (ret != 0)
report = "unknown";
else if (bypass)
report = "enabled";
else
report = "disabled";
return sprintf(buf, "%s\n", report);
}
static DEVICE_ATTR(bypass, 0444,
regulator_bypass_show, NULL);
/* /*
* These are the only attributes are present for all regulators. * These are the only attributes are present for all regulators.
...@@ -2673,6 +2698,100 @@ int regulator_set_optimum_mode(struct regulator *regulator, int uA_load) ...@@ -2673,6 +2698,100 @@ int regulator_set_optimum_mode(struct regulator *regulator, int uA_load)
} }
EXPORT_SYMBOL_GPL(regulator_set_optimum_mode); EXPORT_SYMBOL_GPL(regulator_set_optimum_mode);
/**
* regulator_set_bypass_regmap - Default set_bypass() using regmap
*
* @rdev: device to operate on.
* @enable: state to set.
*/
int regulator_set_bypass_regmap(struct regulator_dev *rdev, bool enable)
{
unsigned int val;
if (enable)
val = rdev->desc->bypass_mask;
else
val = 0;
return regmap_update_bits(rdev->regmap, rdev->desc->bypass_reg,
rdev->desc->bypass_mask, val);
}
EXPORT_SYMBOL_GPL(regulator_set_bypass_regmap);
/**
* regulator_get_bypass_regmap - Default get_bypass() using regmap
*
* @rdev: device to operate on.
* @enable: current state.
*/
int regulator_get_bypass_regmap(struct regulator_dev *rdev, bool *enable)
{
unsigned int val;
int ret;
ret = regmap_read(rdev->regmap, rdev->desc->bypass_reg, &val);
if (ret != 0)
return ret;
*enable = val & rdev->desc->bypass_mask;
return 0;
}
EXPORT_SYMBOL_GPL(regulator_get_bypass_regmap);
/**
* regulator_allow_bypass - allow the regulator to go into bypass mode
*
* @regulator: Regulator to configure
* @allow: enable or disable bypass mode
*
* Allow the regulator to go into bypass mode if all other consumers
* for the regulator also enable bypass mode and the machine
* constraints allow this. Bypass mode means that the regulator is
* simply passing the input directly to the output with no regulation.
*/
int regulator_allow_bypass(struct regulator *regulator, bool enable)
{
struct regulator_dev *rdev = regulator->rdev;
int ret = 0;
if (!rdev->desc->ops->set_bypass)
return 0;
if (rdev->constraints &&
!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_BYPASS))
return 0;
mutex_lock(&rdev->mutex);
if (enable && !regulator->bypass) {
rdev->bypass_count++;
if (rdev->bypass_count == rdev->open_count) {
ret = rdev->desc->ops->set_bypass(rdev, enable);
if (ret != 0)
rdev->bypass_count--;
}
} else if (!enable && regulator->bypass) {
rdev->bypass_count--;
if (rdev->bypass_count != rdev->open_count) {
ret = rdev->desc->ops->set_bypass(rdev, enable);
if (ret != 0)
rdev->bypass_count++;
}
}
if (ret == 0)
regulator->bypass = enable;
mutex_unlock(&rdev->mutex);
return ret;
}
EXPORT_SYMBOL_GPL(regulator_allow_bypass);
/** /**
* regulator_register_notifier - register regulator event notifier * regulator_register_notifier - register regulator event notifier
* @regulator: regulator source * @regulator: regulator source
...@@ -3036,6 +3155,11 @@ static int add_regulator_attributes(struct regulator_dev *rdev) ...@@ -3036,6 +3155,11 @@ static int add_regulator_attributes(struct regulator_dev *rdev)
if (status < 0) if (status < 0)
return status; return status;
} }
if (ops->get_bypass) {
status = device_create_file(dev, &dev_attr_bypass);
if (status < 0)
return status;
}
/* some attributes are type-specific */ /* some attributes are type-specific */
if (rdev->desc->type == REGULATOR_CURRENT) { if (rdev->desc->type == REGULATOR_CURRENT) {
...@@ -3124,6 +3248,8 @@ static void rdev_init_debugfs(struct regulator_dev *rdev) ...@@ -3124,6 +3248,8 @@ static void rdev_init_debugfs(struct regulator_dev *rdev)
&rdev->use_count); &rdev->use_count);
debugfs_create_u32("open_count", 0444, rdev->debugfs, debugfs_create_u32("open_count", 0444, rdev->debugfs,
&rdev->open_count); &rdev->open_count);
debugfs_create_u32("bypass_count", 0444, rdev->debugfs,
&rdev->bypass_count);
} }
/** /**
......
...@@ -237,6 +237,8 @@ static struct regulator_ops wm831x_gp_ldo_ops = { ...@@ -237,6 +237,8 @@ static struct regulator_ops wm831x_gp_ldo_ops = {
.set_mode = wm831x_gp_ldo_set_mode, .set_mode = wm831x_gp_ldo_set_mode,
.get_status = wm831x_gp_ldo_get_status, .get_status = wm831x_gp_ldo_get_status,
.get_optimum_mode = wm831x_gp_ldo_get_optimum_mode, .get_optimum_mode = wm831x_gp_ldo_get_optimum_mode,
.get_bypass = regulator_get_bypass_regmap,
.set_bypass = regulator_set_bypass_regmap,
.is_enabled = regulator_is_enabled_regmap, .is_enabled = regulator_is_enabled_regmap,
.enable = regulator_enable_regmap, .enable = regulator_enable_regmap,
...@@ -293,6 +295,8 @@ static __devinit int wm831x_gp_ldo_probe(struct platform_device *pdev) ...@@ -293,6 +295,8 @@ static __devinit int wm831x_gp_ldo_probe(struct platform_device *pdev)
ldo->desc.vsel_mask = WM831X_LDO1_ON_VSEL_MASK; ldo->desc.vsel_mask = WM831X_LDO1_ON_VSEL_MASK;
ldo->desc.enable_reg = WM831X_LDO_ENABLE; ldo->desc.enable_reg = WM831X_LDO_ENABLE;
ldo->desc.enable_mask = 1 << id; ldo->desc.enable_mask = 1 << id;
ldo->desc.bypass_reg = ldo->base;
ldo->desc.bypass_mask = WM831X_LDO1_SWI;
config.dev = pdev->dev.parent; config.dev = pdev->dev.parent;
if (pdata) if (pdata)
...@@ -488,6 +492,8 @@ static struct regulator_ops wm831x_aldo_ops = { ...@@ -488,6 +492,8 @@ static struct regulator_ops wm831x_aldo_ops = {
.get_mode = wm831x_aldo_get_mode, .get_mode = wm831x_aldo_get_mode,
.set_mode = wm831x_aldo_set_mode, .set_mode = wm831x_aldo_set_mode,
.get_status = wm831x_aldo_get_status, .get_status = wm831x_aldo_get_status,
.set_bypass = regulator_set_bypass_regmap,
.get_bypass = regulator_get_bypass_regmap,
.is_enabled = regulator_is_enabled_regmap, .is_enabled = regulator_is_enabled_regmap,
.enable = regulator_enable_regmap, .enable = regulator_enable_regmap,
...@@ -544,6 +550,8 @@ static __devinit int wm831x_aldo_probe(struct platform_device *pdev) ...@@ -544,6 +550,8 @@ static __devinit int wm831x_aldo_probe(struct platform_device *pdev)
ldo->desc.vsel_mask = WM831X_LDO7_ON_VSEL_MASK; ldo->desc.vsel_mask = WM831X_LDO7_ON_VSEL_MASK;
ldo->desc.enable_reg = WM831X_LDO_ENABLE; ldo->desc.enable_reg = WM831X_LDO_ENABLE;
ldo->desc.enable_mask = 1 << id; ldo->desc.enable_mask = 1 << id;
ldo->desc.bypass_reg = ldo->base;
ldo->desc.bypass_mask = WM831X_LDO7_SWI;
config.dev = pdev->dev.parent; config.dev = pdev->dev.parent;
if (pdata) if (pdata)
......
...@@ -23,7 +23,8 @@ enum amic_type { ...@@ -23,7 +23,8 @@ enum amic_type {
/* Mic-biases */ /* Mic-biases */
enum amic_micbias { enum amic_micbias {
AMIC_MICBIAS_VAMIC1, AMIC_MICBIAS_VAMIC1,
AMIC_MICBIAS_VAMIC2 AMIC_MICBIAS_VAMIC2,
AMIC_MICBIAS_UNKNOWN
}; };
/* Bias-voltage */ /* Bias-voltage */
...@@ -31,7 +32,8 @@ enum ear_cm_voltage { ...@@ -31,7 +32,8 @@ enum ear_cm_voltage {
EAR_CMV_0_95V, EAR_CMV_0_95V,
EAR_CMV_1_10V, EAR_CMV_1_10V,
EAR_CMV_1_27V, EAR_CMV_1_27V,
EAR_CMV_1_58V EAR_CMV_1_58V,
EAR_CMV_UNKNOWN
}; };
/* Analog microphone settings */ /* Analog microphone settings */
......
...@@ -177,6 +177,8 @@ int regulator_set_mode(struct regulator *regulator, unsigned int mode); ...@@ -177,6 +177,8 @@ int regulator_set_mode(struct regulator *regulator, unsigned int mode);
unsigned int regulator_get_mode(struct regulator *regulator); unsigned int regulator_get_mode(struct regulator *regulator);
int regulator_set_optimum_mode(struct regulator *regulator, int load_uA); int regulator_set_optimum_mode(struct regulator *regulator, int load_uA);
int regulator_allow_bypass(struct regulator *regulator, bool allow);
/* regulator notifier block */ /* regulator notifier block */
int regulator_register_notifier(struct regulator *regulator, int regulator_register_notifier(struct regulator *regulator,
struct notifier_block *nb); struct notifier_block *nb);
...@@ -328,6 +330,12 @@ static inline int regulator_set_optimum_mode(struct regulator *regulator, ...@@ -328,6 +330,12 @@ static inline int regulator_set_optimum_mode(struct regulator *regulator,
return REGULATOR_MODE_NORMAL; return REGULATOR_MODE_NORMAL;
} }
static inline int regulator_allow_bypass(struct regulator *regulator,
bool allow)
{
return 0;
}
static inline int regulator_register_notifier(struct regulator *regulator, static inline int regulator_register_notifier(struct regulator *regulator,
struct notifier_block *nb) struct notifier_block *nb)
{ {
......
...@@ -32,6 +32,8 @@ enum regulator_status { ...@@ -32,6 +32,8 @@ enum regulator_status {
REGULATOR_STATUS_NORMAL, REGULATOR_STATUS_NORMAL,
REGULATOR_STATUS_IDLE, REGULATOR_STATUS_IDLE,
REGULATOR_STATUS_STANDBY, REGULATOR_STATUS_STANDBY,
/* The regulator is enabled but not regulating */
REGULATOR_STATUS_BYPASS,
/* in case that any other status doesn't apply */ /* in case that any other status doesn't apply */
REGULATOR_STATUS_UNDEFINED, REGULATOR_STATUS_UNDEFINED,
}; };
...@@ -67,6 +69,9 @@ enum regulator_status { ...@@ -67,6 +69,9 @@ enum regulator_status {
* @get_optimum_mode: Get the most efficient operating mode for the regulator * @get_optimum_mode: Get the most efficient operating mode for the regulator
* when running with the specified parameters. * when running with the specified parameters.
* *
* @set_bypass: Set the regulator in bypass mode.
* @get_bypass: Get the regulator bypass mode state.
*
* @enable_time: Time taken for the regulator voltage output voltage to * @enable_time: Time taken for the regulator voltage output voltage to
* stabilise after being enabled, in microseconds. * stabilise after being enabled, in microseconds.
* @set_ramp_delay: Set the ramp delay for the regulator. The driver should * @set_ramp_delay: Set the ramp delay for the regulator. The driver should
...@@ -133,6 +138,10 @@ struct regulator_ops { ...@@ -133,6 +138,10 @@ struct regulator_ops {
unsigned int (*get_optimum_mode) (struct regulator_dev *, int input_uV, unsigned int (*get_optimum_mode) (struct regulator_dev *, int input_uV,
int output_uV, int load_uA); int output_uV, int load_uA);
/* control and report on bypass mode */
int (*set_bypass)(struct regulator_dev *dev, bool enable);
int (*get_bypass)(struct regulator_dev *dev, bool *enable);
/* the operations below are for configuration of regulator state when /* the operations below are for configuration of regulator state when
* its parent PMIC enters a global STANDBY/HIBERNATE state */ * its parent PMIC enters a global STANDBY/HIBERNATE state */
...@@ -205,6 +214,8 @@ struct regulator_desc { ...@@ -205,6 +214,8 @@ struct regulator_desc {
unsigned int vsel_mask; unsigned int vsel_mask;
unsigned int enable_reg; unsigned int enable_reg;
unsigned int enable_mask; unsigned int enable_mask;
unsigned int bypass_reg;
unsigned int bypass_mask;
unsigned int enable_time; unsigned int enable_time;
}; };
...@@ -253,6 +264,7 @@ struct regulator_dev { ...@@ -253,6 +264,7 @@ struct regulator_dev {
int exclusive; int exclusive;
u32 use_count; u32 use_count;
u32 open_count; u32 open_count;
u32 bypass_count;
/* lists we belong to */ /* lists we belong to */
struct list_head list; /* list of all regulators */ struct list_head list; /* list of all regulators */
...@@ -310,6 +322,8 @@ int regulator_disable_regmap(struct regulator_dev *rdev); ...@@ -310,6 +322,8 @@ int regulator_disable_regmap(struct regulator_dev *rdev);
int regulator_set_voltage_time_sel(struct regulator_dev *rdev, int regulator_set_voltage_time_sel(struct regulator_dev *rdev,
unsigned int old_selector, unsigned int old_selector,
unsigned int new_selector); unsigned int new_selector);
int regulator_set_bypass_regmap(struct regulator_dev *rdev, bool enable);
int regulator_get_bypass_regmap(struct regulator_dev *rdev, bool *enable);
void *regulator_get_init_drvdata(struct regulator_init_data *reg_init_data); void *regulator_get_init_drvdata(struct regulator_init_data *reg_init_data);
......
...@@ -32,6 +32,7 @@ struct regulator; ...@@ -32,6 +32,7 @@ struct regulator;
* board/machine. * board/machine.
* STATUS: Regulator can be enabled and disabled. * STATUS: Regulator can be enabled and disabled.
* DRMS: Dynamic Regulator Mode Switching is enabled for this regulator. * DRMS: Dynamic Regulator Mode Switching is enabled for this regulator.
* BYPASS: Regulator can be put into bypass mode
*/ */
#define REGULATOR_CHANGE_VOLTAGE 0x1 #define REGULATOR_CHANGE_VOLTAGE 0x1
...@@ -39,6 +40,7 @@ struct regulator; ...@@ -39,6 +40,7 @@ struct regulator;
#define REGULATOR_CHANGE_MODE 0x4 #define REGULATOR_CHANGE_MODE 0x4
#define REGULATOR_CHANGE_STATUS 0x8 #define REGULATOR_CHANGE_STATUS 0x8
#define REGULATOR_CHANGE_DRMS 0x10 #define REGULATOR_CHANGE_DRMS 0x10
#define REGULATOR_CHANGE_BYPASS 0x20
/** /**
* struct regulator_state - regulator state during low power system states * struct regulator_state - regulator state during low power system states
......
/*
* DA9055 ALSA Soc codec driver
*
* Copyright (c) 2012 Dialog Semiconductor
*
* Tested on (Samsung SMDK6410 board + DA9055 EVB) using I2S and I2C
* Written by David Chen <david.chen@diasemi.com> and
* Ashish Chavan <ashish.chavan@kpitcummins.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.
*/
#ifndef __SOUND_DA9055_H__
#define __SOUND_DA9055_H__
enum da9055_micbias_voltage {
DA9055_MICBIAS_1_6V = 0,
DA9055_MICBIAS_1_8V = 1,
DA9055_MICBIAS_2_1V = 2,
DA9055_MICBIAS_2_2V = 3,
};
struct da9055_platform_data {
/* Selects which of the two MicBias pins acts as the bias source */
bool micbias_source;
/* Selects the micbias voltage */
enum da9055_micbias_voltage micbias;
};
#endif
...@@ -320,6 +320,9 @@ struct device; ...@@ -320,6 +320,9 @@ struct device;
#define SND_SOC_DAPM_EVENT_OFF(e) \ #define SND_SOC_DAPM_EVENT_OFF(e) \
(e & (SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD)) (e & (SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD))
/* regulator widget flags */
#define SND_SOC_DAPM_REGULATOR_BYPASS 0x1 /* bypass when disabled */
struct snd_soc_dapm_widget; struct snd_soc_dapm_widget;
enum snd_soc_dapm_type; enum snd_soc_dapm_type;
struct snd_soc_dapm_path; struct snd_soc_dapm_path;
......
...@@ -37,6 +37,7 @@ config SND_SOC_ALL_CODECS ...@@ -37,6 +37,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_CX20442 select SND_SOC_CX20442
select SND_SOC_DA7210 if I2C select SND_SOC_DA7210 if I2C
select SND_SOC_DA732X if I2C select SND_SOC_DA732X if I2C
select SND_SOC_DA9055 if I2C
select SND_SOC_DFBMCS320 select SND_SOC_DFBMCS320
select SND_SOC_ISABELLE if I2C select SND_SOC_ISABELLE if I2C
select SND_SOC_JZ4740_CODEC select SND_SOC_JZ4740_CODEC
...@@ -239,6 +240,9 @@ config SND_SOC_DA7210 ...@@ -239,6 +240,9 @@ config SND_SOC_DA7210
config SND_SOC_DA732X config SND_SOC_DA732X
tristate tristate
config SND_SOC_DA9055
tristate
config SND_SOC_DFBMCS320 config SND_SOC_DFBMCS320
tristate tristate
......
...@@ -24,6 +24,7 @@ snd-soc-cs4271-objs := cs4271.o ...@@ -24,6 +24,7 @@ snd-soc-cs4271-objs := cs4271.o
snd-soc-cx20442-objs := cx20442.o snd-soc-cx20442-objs := cx20442.o
snd-soc-da7210-objs := da7210.o snd-soc-da7210-objs := da7210.o
snd-soc-da732x-objs := da732x.o snd-soc-da732x-objs := da732x.o
snd-soc-da9055-objs := da9055.o
snd-soc-dfbmcs320-objs := dfbmcs320.o snd-soc-dfbmcs320-objs := dfbmcs320.o
snd-soc-dmic-objs := dmic.o snd-soc-dmic-objs := dmic.o
snd-soc-isabelle-objs := isabelle.o snd-soc-isabelle-objs := isabelle.o
...@@ -144,6 +145,7 @@ obj-$(CONFIG_SND_SOC_CS4271) += snd-soc-cs4271.o ...@@ -144,6 +145,7 @@ obj-$(CONFIG_SND_SOC_CS4271) += snd-soc-cs4271.o
obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o
obj-$(CONFIG_SND_SOC_DA7210) += snd-soc-da7210.o obj-$(CONFIG_SND_SOC_DA7210) += snd-soc-da7210.o
obj-$(CONFIG_SND_SOC_DA732X) += snd-soc-da732x.o obj-$(CONFIG_SND_SOC_DA732X) += snd-soc-da732x.o
obj-$(CONFIG_SND_SOC_DA9055) += snd-soc-da9055.o
obj-$(CONFIG_SND_SOC_DFBMCS320) += snd-soc-dfbmcs320.o obj-$(CONFIG_SND_SOC_DFBMCS320) += snd-soc-dfbmcs320.o
obj-$(CONFIG_SND_SOC_DMIC) += snd-soc-dmic.o obj-$(CONFIG_SND_SOC_DMIC) += snd-soc-dmic.o
obj-$(CONFIG_SND_SOC_ISABELLE) += snd-soc-isabelle.o obj-$(CONFIG_SND_SOC_ISABELLE) += snd-soc-isabelle.o
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include <linux/mfd/abx500/ab8500-sysctrl.h> #include <linux/mfd/abx500/ab8500-sysctrl.h>
#include <linux/mfd/abx500/ab8500-codec.h> #include <linux/mfd/abx500/ab8500-codec.h>
#include <linux/regulator/consumer.h> #include <linux/regulator/consumer.h>
#include <linux/of.h>
#include <sound/core.h> #include <sound/core.h>
#include <sound/pcm.h> #include <sound/pcm.h>
...@@ -2394,9 +2395,65 @@ struct snd_soc_dai_driver ab8500_codec_dai[] = { ...@@ -2394,9 +2395,65 @@ struct snd_soc_dai_driver ab8500_codec_dai[] = {
} }
}; };
static void ab8500_codec_of_probe(struct device *dev, struct device_node *np,
struct ab8500_codec_platform_data *codec)
{
u32 value;
if (of_get_property(np, "stericsson,amic1-type-single-ended", NULL))
codec->amics.mic1_type = AMIC_TYPE_SINGLE_ENDED;
else
codec->amics.mic1_type = AMIC_TYPE_DIFFERENTIAL;
if (of_get_property(np, "stericsson,amic2-type-single-ended", NULL))
codec->amics.mic2_type = AMIC_TYPE_SINGLE_ENDED;
else
codec->amics.mic2_type = AMIC_TYPE_DIFFERENTIAL;
/* Has a non-standard Vamic been requested? */
if (of_get_property(np, "stericsson,amic1a-bias-vamic2", NULL))
codec->amics.mic1a_micbias = AMIC_MICBIAS_VAMIC2;
else
codec->amics.mic1a_micbias = AMIC_MICBIAS_VAMIC1;
if (of_get_property(np, "stericsson,amic1b-bias-vamic2", NULL))
codec->amics.mic1b_micbias = AMIC_MICBIAS_VAMIC2;
else
codec->amics.mic1b_micbias = AMIC_MICBIAS_VAMIC1;
if (of_get_property(np, "stericsson,amic2-bias-vamic1", NULL))
codec->amics.mic2_micbias = AMIC_MICBIAS_VAMIC1;
else
codec->amics.mic2_micbias = AMIC_MICBIAS_VAMIC2;
if (!of_property_read_u32(np, "stericsson,earpeice-cmv", &value)) {
switch (value) {
case 950 :
codec->ear_cmv = EAR_CMV_0_95V;
break;
case 1100 :
codec->ear_cmv = EAR_CMV_1_10V;
break;
case 1270 :
codec->ear_cmv = EAR_CMV_1_27V;
break;
case 1580 :
codec->ear_cmv = EAR_CMV_1_58V;
break;
default :
codec->ear_cmv = EAR_CMV_UNKNOWN;
dev_err(dev, "Unsuitable earpiece voltage found in DT\n");
}
} else {
dev_warn(dev, "No earpiece voltage found in DT - using default\n");
codec->ear_cmv = EAR_CMV_0_95V;
}
}
static int ab8500_codec_probe(struct snd_soc_codec *codec) static int ab8500_codec_probe(struct snd_soc_codec *codec)
{ {
struct device *dev = codec->dev; struct device *dev = codec->dev;
struct device_node *np = dev->of_node;
struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(dev); struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(dev);
struct ab8500_platform_data *pdata; struct ab8500_platform_data *pdata;
struct filter_control *fc; struct filter_control *fc;
...@@ -2407,6 +2464,30 @@ static int ab8500_codec_probe(struct snd_soc_codec *codec) ...@@ -2407,6 +2464,30 @@ static int ab8500_codec_probe(struct snd_soc_codec *codec)
/* Setup AB8500 according to board-settings */ /* Setup AB8500 according to board-settings */
pdata = dev_get_platdata(dev->parent); pdata = dev_get_platdata(dev->parent);
if (np) {
if (!pdata)
pdata = devm_kzalloc(dev,
sizeof(struct ab8500_platform_data),
GFP_KERNEL);
if (pdata && !pdata->codec)
pdata->codec
= devm_kzalloc(dev,
sizeof(struct ab8500_codec_platform_data),
GFP_KERNEL);
if (!(pdata && pdata->codec))
return -ENOMEM;
ab8500_codec_of_probe(dev, np, pdata->codec);
} else {
if (!(pdata && pdata->codec)) {
dev_err(dev, "No codec platform data or DT found\n");
return -EINVAL;
}
}
status = ab8500_audio_setup_mics(codec, &pdata->codec->amics); status = ab8500_audio_setup_mics(codec, &pdata->codec->amics);
if (status < 0) { if (status < 0) {
pr_err("%s: Failed to setup mics (%d)!\n", __func__, status); pr_err("%s: Failed to setup mics (%d)!\n", __func__, status);
......
...@@ -119,6 +119,24 @@ const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = { ...@@ -119,6 +119,24 @@ const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = {
"DSP1.4", "DSP1.4",
"DSP1.5", "DSP1.5",
"DSP1.6", "DSP1.6",
"DSP2.1",
"DSP2.2",
"DSP2.3",
"DSP2.4",
"DSP2.5",
"DSP2.6",
"DSP3.1",
"DSP3.2",
"DSP3.3",
"DSP3.4",
"DSP3.5",
"DSP3.6",
"DSP4.1",
"DSP4.2",
"DSP4.3",
"DSP4.4",
"DSP4.5",
"DSP4.6",
"ASRC1L", "ASRC1L",
"ASRC1R", "ASRC1R",
"ASRC2L", "ASRC2L",
...@@ -180,6 +198,24 @@ int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS] = { ...@@ -180,6 +198,24 @@ int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS] = {
0x6b, 0x6b,
0x6c, 0x6c,
0x6d, 0x6d,
0x70, /* DSP2.1 */
0x71,
0x72,
0x73,
0x74,
0x75,
0x78, /* DSP3.1 */
0x79,
0x7a,
0x7b,
0x7c,
0x7d,
0x80, /* DSP4.1 */
0x81,
0x82,
0x83,
0x84,
0x85,
0x90, /* ASRC1L */ 0x90, /* ASRC1L */
0x91, 0x91,
0x92, 0x92,
...@@ -234,6 +270,9 @@ static unsigned int arizona_sysclk_48k_rates[] = { ...@@ -234,6 +270,9 @@ static unsigned int arizona_sysclk_48k_rates[] = {
12288000, 12288000,
22579200, 22579200,
49152000, 49152000,
73728000,
98304000,
147456000,
}; };
static unsigned int arizona_sysclk_44k1_rates[] = { static unsigned int arizona_sysclk_44k1_rates[] = {
...@@ -241,6 +280,9 @@ static unsigned int arizona_sysclk_44k1_rates[] = { ...@@ -241,6 +280,9 @@ static unsigned int arizona_sysclk_44k1_rates[] = {
11289600, 11289600,
24576000, 24576000,
45158400, 45158400,
67737600,
90316800,
135475200,
}; };
static int arizona_set_opclk(struct snd_soc_codec *codec, unsigned int clk, static int arizona_set_opclk(struct snd_soc_codec *codec, unsigned int clk,
......
...@@ -61,7 +61,7 @@ struct arizona_priv { ...@@ -61,7 +61,7 @@ struct arizona_priv {
struct arizona_dai_priv dai[ARIZONA_MAX_DAI]; struct arizona_dai_priv dai[ARIZONA_MAX_DAI];
}; };
#define ARIZONA_NUM_MIXER_INPUTS 57 #define ARIZONA_NUM_MIXER_INPUTS 75
extern const unsigned int arizona_mixer_tlv[]; extern const unsigned int arizona_mixer_tlv[];
extern const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS]; extern const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS];
......
...@@ -459,7 +459,7 @@ static struct snd_soc_dai_driver cs4270_dai = { ...@@ -459,7 +459,7 @@ static struct snd_soc_dai_driver cs4270_dai = {
.name = "cs4270-hifi", .name = "cs4270-hifi",
.playback = { .playback = {
.stream_name = "Playback", .stream_name = "Playback",
.channels_min = 1, .channels_min = 2,
.channels_max = 2, .channels_max = 2,
.rates = SNDRV_PCM_RATE_CONTINUOUS, .rates = SNDRV_PCM_RATE_CONTINUOUS,
.rate_min = 4000, .rate_min = 4000,
...@@ -468,7 +468,7 @@ static struct snd_soc_dai_driver cs4270_dai = { ...@@ -468,7 +468,7 @@ static struct snd_soc_dai_driver cs4270_dai = {
}, },
.capture = { .capture = {
.stream_name = "Capture", .stream_name = "Capture",
.channels_min = 1, .channels_min = 2,
.channels_max = 2, .channels_max = 2,
.rates = SNDRV_PCM_RATE_CONTINUOUS, .rates = SNDRV_PCM_RATE_CONTINUOUS,
.rate_min = 4000, .rate_min = 4000,
......
...@@ -22,12 +22,14 @@ ...@@ -22,12 +22,14 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/tlv.h>
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/tlv.h>
#include <sound/cs4271.h> #include <sound/cs4271.h>
#define CS4271_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ #define CS4271_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
...@@ -458,6 +460,14 @@ static int cs4271_soc_resume(struct snd_soc_codec *codec) ...@@ -458,6 +460,14 @@ static int cs4271_soc_resume(struct snd_soc_codec *codec)
#define cs4271_soc_resume NULL #define cs4271_soc_resume NULL
#endif /* CONFIG_PM */ #endif /* CONFIG_PM */
#ifdef CONFIG_OF
static const struct of_device_id cs4271_dt_ids[] = {
{ .compatible = "cirrus,cs4271", },
{ }
};
MODULE_DEVICE_TABLE(of, cs4271_dt_ids);
#endif
static int cs4271_probe(struct snd_soc_codec *codec) static int cs4271_probe(struct snd_soc_codec *codec)
{ {
struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec); struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
...@@ -465,6 +475,12 @@ static int cs4271_probe(struct snd_soc_codec *codec) ...@@ -465,6 +475,12 @@ static int cs4271_probe(struct snd_soc_codec *codec)
int ret; int ret;
int gpio_nreset = -EINVAL; int gpio_nreset = -EINVAL;
#ifdef CONFIG_OF
if (of_match_device(cs4271_dt_ids, codec->dev))
gpio_nreset = of_get_named_gpio(codec->dev->of_node,
"reset-gpio", 0);
#endif
if (cs4271plat && gpio_is_valid(cs4271plat->gpio_nreset)) if (cs4271plat && gpio_is_valid(cs4271plat->gpio_nreset))
gpio_nreset = cs4271plat->gpio_nreset; gpio_nreset = cs4271plat->gpio_nreset;
...@@ -569,6 +585,7 @@ static struct spi_driver cs4271_spi_driver = { ...@@ -569,6 +585,7 @@ static struct spi_driver cs4271_spi_driver = {
.driver = { .driver = {
.name = "cs4271", .name = "cs4271",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.of_match_table = of_match_ptr(cs4271_dt_ids),
}, },
.probe = cs4271_spi_probe, .probe = cs4271_spi_probe,
.remove = __devexit_p(cs4271_spi_remove), .remove = __devexit_p(cs4271_spi_remove),
...@@ -608,6 +625,7 @@ static struct i2c_driver cs4271_i2c_driver = { ...@@ -608,6 +625,7 @@ static struct i2c_driver cs4271_i2c_driver = {
.driver = { .driver = {
.name = "cs4271", .name = "cs4271",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.of_match_table = of_match_ptr(cs4271_dt_ids),
}, },
.id_table = cs4271_i2c_id, .id_table = cs4271_i2c_id,
.probe = cs4271_i2c_probe, .probe = cs4271_i2c_probe,
......
This diff is collapsed.
...@@ -168,7 +168,8 @@ static void wm0010_halt(struct snd_soc_codec *codec) ...@@ -168,7 +168,8 @@ static void wm0010_halt(struct snd_soc_codec *codec)
case WM0010_STAGE2: case WM0010_STAGE2:
case WM0010_FIRMWARE: case WM0010_FIRMWARE:
/* Remember to put chip back into reset */ /* Remember to put chip back into reset */
gpio_set_value(wm0010->gpio_reset, wm0010->gpio_reset_value); gpio_set_value_cansleep(wm0010->gpio_reset,
wm0010->gpio_reset_value);
/* Disable the regulators */ /* Disable the regulators */
regulator_disable(wm0010->dbvdd); regulator_disable(wm0010->dbvdd);
regulator_bulk_disable(ARRAY_SIZE(wm0010->core_supplies), regulator_bulk_disable(ARRAY_SIZE(wm0010->core_supplies),
...@@ -387,7 +388,7 @@ static int wm0010_boot(struct snd_soc_codec *codec) ...@@ -387,7 +388,7 @@ static int wm0010_boot(struct snd_soc_codec *codec)
} }
/* Release reset */ /* Release reset */
gpio_set_value(wm0010->gpio_reset, !wm0010->gpio_reset_value); gpio_set_value_cansleep(wm0010->gpio_reset, !wm0010->gpio_reset_value);
spin_lock_irqsave(&wm0010->irq_lock, flags); spin_lock_irqsave(&wm0010->irq_lock, flags);
wm0010->state = WM0010_OUT_OF_RESET; wm0010->state = WM0010_OUT_OF_RESET;
spin_unlock_irqrestore(&wm0010->irq_lock, flags); spin_unlock_irqrestore(&wm0010->irq_lock, flags);
...@@ -809,7 +810,6 @@ static int wm0010_probe(struct snd_soc_codec *codec) ...@@ -809,7 +810,6 @@ static int wm0010_probe(struct snd_soc_codec *codec)
static int __devinit wm0010_spi_probe(struct spi_device *spi) static int __devinit wm0010_spi_probe(struct spi_device *spi)
{ {
unsigned long flags;
unsigned long gpio_flags; unsigned long gpio_flags;
int ret; int ret;
int trigger; int trigger;
...@@ -876,6 +876,8 @@ static int __devinit wm0010_spi_probe(struct spi_device *spi) ...@@ -876,6 +876,8 @@ static int __devinit wm0010_spi_probe(struct spi_device *spi)
return -EINVAL; return -EINVAL;
} }
wm0010->state = WM0010_POWER_OFF;
irq = spi->irq; irq = spi->irq;
if (wm0010->pdata.irq_flags) if (wm0010->pdata.irq_flags)
trigger = wm0010->pdata.irq_flags; trigger = wm0010->pdata.irq_flags;
...@@ -897,10 +899,6 @@ static int __devinit wm0010_spi_probe(struct spi_device *spi) ...@@ -897,10 +899,6 @@ static int __devinit wm0010_spi_probe(struct spi_device *spi)
else else
wm0010->board_max_spi_speed = 0; wm0010->board_max_spi_speed = 0;
spin_lock_irqsave(&wm0010->irq_lock, flags);
wm0010->state = WM0010_POWER_OFF;
spin_unlock_irqrestore(&wm0010->irq_lock, flags);
ret = snd_soc_register_codec(&spi->dev, ret = snd_soc_register_codec(&spi->dev,
&soc_codec_dev_wm0010, wm0010_dai, &soc_codec_dev_wm0010, wm0010_dai,
ARRAY_SIZE(wm0010_dai)); ARRAY_SIZE(wm0010_dai));
...@@ -916,10 +914,8 @@ static int __devexit wm0010_spi_remove(struct spi_device *spi) ...@@ -916,10 +914,8 @@ static int __devexit wm0010_spi_remove(struct spi_device *spi)
snd_soc_unregister_codec(&spi->dev); snd_soc_unregister_codec(&spi->dev);
if (wm0010->gpio_reset) { gpio_set_value_cansleep(wm0010->gpio_reset,
/* Remember to put chip back into reset */ wm0010->gpio_reset_value);
gpio_set_value(wm0010->gpio_reset, wm0010->gpio_reset_value);
}
if (wm0010->irq) if (wm0010->irq)
free_irq(wm0010->irq, wm0010); free_irq(wm0010->irq, wm0010);
......
...@@ -31,6 +31,7 @@ ...@@ -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 @@ ...@@ -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 { ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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;
...@@ -760,7 +784,7 @@ static int __devinit wm2000_i2c_probe(struct i2c_client *i2c, ...@@ -760,7 +784,7 @@ static int __devinit wm2000_i2c_probe(struct i2c_client *i2c,
dev_set_drvdata(&i2c->dev, wm2000); dev_set_drvdata(&i2c->dev, wm2000);
wm2000->regmap = regmap_init_i2c(i2c, &wm2000_regmap); wm2000->regmap = devm_regmap_init_i2c(i2c, &wm2000_regmap);
if (IS_ERR(wm2000->regmap)) { if (IS_ERR(wm2000->regmap)) {
ret = PTR_ERR(wm2000->regmap); ret = PTR_ERR(wm2000->regmap);
dev_err(&i2c->dev, "Failed to allocate register map: %d\n", dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
...@@ -768,6 +792,22 @@ static int __devinit wm2000_i2c_probe(struct i2c_client *i2c, ...@@ -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, ...@@ -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_regmap_exit; 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, ...@@ -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_regmap_exit; 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, ...@@ -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_regmap_exit; goto err_supplies;
} }
wm2000->anc_download[0] = 0x80; wm2000->anc_download[0] = 0x80;
...@@ -822,11 +862,10 @@ static int __devinit wm2000_i2c_probe(struct i2c_client *i2c, ...@@ -822,11 +862,10 @@ 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;
out_regmap_exit: err_supplies:
regmap_exit(wm2000->regmap); regulator_bulk_disable(WM2000_NUM_SUPPLIES, wm2000->supplies);
out: out:
release_firmware(fw); release_firmware(fw);
return ret; return ret;
...@@ -834,10 +873,7 @@ static int __devinit wm2000_i2c_probe(struct i2c_client *i2c, ...@@ -834,10 +873,7 @@ static int __devinit wm2000_i2c_probe(struct i2c_client *i2c,
static __devexit int wm2000_i2c_remove(struct i2c_client *i2c) static __devexit int wm2000_i2c_remove(struct i2c_client *i2c)
{ {
struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev);
snd_soc_unregister_codec(&i2c->dev); snd_soc_unregister_codec(&i2c->dev);
regmap_exit(wm2000->regmap);
return 0; return 0;
} }
......
...@@ -308,7 +308,7 @@ SND_SOC_DAPM_SUPPLY("ASYNCOPCLK", ARIZONA_OUTPUT_ASYNC_CLOCK, ...@@ -308,7 +308,7 @@ SND_SOC_DAPM_SUPPLY("ASYNCOPCLK", ARIZONA_OUTPUT_ASYNC_CLOCK,
SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD2", 0, 0), SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD2", 0, 0),
SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD3", 0, 0), SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD3", 0, 0),
SND_SOC_DAPM_REGULATOR_SUPPLY("CPVDD", 20, 0), SND_SOC_DAPM_REGULATOR_SUPPLY("CPVDD", 20, 0),
SND_SOC_DAPM_REGULATOR_SUPPLY("MICVDD", 0, 0), SND_SOC_DAPM_REGULATOR_SUPPLY("MICVDD", 0, SND_SOC_DAPM_REGULATOR_BYPASS),
SND_SOC_DAPM_REGULATOR_SUPPLY("SPKVDDL", 0, 0), SND_SOC_DAPM_REGULATOR_SUPPLY("SPKVDDL", 0, 0),
SND_SOC_DAPM_REGULATOR_SUPPLY("SPKVDDR", 0, 0), SND_SOC_DAPM_REGULATOR_SUPPLY("SPKVDDR", 0, 0),
......
This diff is collapsed.
...@@ -681,6 +681,11 @@ void wm_hubs_update_class_w(struct snd_soc_codec *codec) ...@@ -681,6 +681,11 @@ void wm_hubs_update_class_w(struct snd_soc_codec *codec)
snd_soc_update_bits(codec, WM8993_CLASS_W_0, snd_soc_update_bits(codec, WM8993_CLASS_W_0,
WM8993_CP_DYN_V | WM8993_CP_DYN_FREQ, enable); WM8993_CP_DYN_V | WM8993_CP_DYN_FREQ, enable);
snd_soc_write(codec, WM8993_LEFT_OUTPUT_VOLUME,
snd_soc_read(codec, WM8993_LEFT_OUTPUT_VOLUME));
snd_soc_write(codec, WM8993_RIGHT_OUTPUT_VOLUME,
snd_soc_read(codec, WM8993_RIGHT_OUTPUT_VOLUME));
} }
EXPORT_SYMBOL_GPL(wm_hubs_update_class_w); EXPORT_SYMBOL_GPL(wm_hubs_update_class_w);
......
...@@ -93,9 +93,7 @@ static struct snd_soc_card eukrea_tlv320 = { ...@@ -93,9 +93,7 @@ static struct snd_soc_card eukrea_tlv320 = {
.num_links = 1, .num_links = 1,
}; };
static struct platform_device *eukrea_tlv320_snd_device; static int __devinit eukrea_tlv320_probe(struct platform_device *pdev)
static int __init eukrea_tlv320_init(void)
{ {
int ret; int ret;
int int_port = 0, ext_port; int int_port = 0, ext_port;
...@@ -136,29 +134,32 @@ static int __init eukrea_tlv320_init(void) ...@@ -136,29 +134,32 @@ static int __init eukrea_tlv320_init(void)
return 0; return 0;
} }
eukrea_tlv320_snd_device = platform_device_alloc("soc-audio", -1); eukrea_tlv320.dev = &pdev->dev;
if (!eukrea_tlv320_snd_device) ret = snd_soc_register_card(&eukrea_tlv320);
return -ENOMEM; if (ret)
dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
platform_set_drvdata(eukrea_tlv320_snd_device, &eukrea_tlv320);
ret = platform_device_add(eukrea_tlv320_snd_device);
if (ret) {
printk(KERN_ERR "ASoC: Platform device allocation failed\n");
platform_device_put(eukrea_tlv320_snd_device);
}
return ret; return ret;
} }
static void __exit eukrea_tlv320_exit(void) static int __devexit eukrea_tlv320_remove(struct platform_device *pdev)
{ {
platform_device_unregister(eukrea_tlv320_snd_device); snd_soc_unregister_card(&eukrea_tlv320);
return 0;
} }
module_init(eukrea_tlv320_init); static struct platform_driver eukrea_tlv320_driver = {
module_exit(eukrea_tlv320_exit); .driver = {
.name = "eukrea_tlv320",
.owner = THIS_MODULE,
},
.probe = eukrea_tlv320_probe,
.remove = __devexit_p(eukrea_tlv320_remove),};
module_platform_driver(eukrea_tlv320_driver);
MODULE_AUTHOR("Eric Bénard <eric@eukrea.com>"); MODULE_AUTHOR("Eric Bénard <eric@eukrea.com>");
MODULE_DESCRIPTION("CPUIMX ALSA SoC driver"); MODULE_DESCRIPTION("CPUIMX ALSA SoC driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:eukrea_tlv320");
...@@ -1017,10 +1017,29 @@ EXPORT_SYMBOL_GPL(dapm_reg_event); ...@@ -1017,10 +1017,29 @@ EXPORT_SYMBOL_GPL(dapm_reg_event);
int dapm_regulator_event(struct snd_soc_dapm_widget *w, int dapm_regulator_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event) struct snd_kcontrol *kcontrol, int event)
{ {
if (SND_SOC_DAPM_EVENT_ON(event)) int ret;
if (SND_SOC_DAPM_EVENT_ON(event)) {
if (w->invert & SND_SOC_DAPM_REGULATOR_BYPASS) {
ret = regulator_allow_bypass(w->regulator, true);
if (ret != 0)
dev_warn(w->dapm->dev,
"Failed to bypass %s: %d\n",
w->name, ret);
}
return regulator_enable(w->regulator); return regulator_enable(w->regulator);
else } else {
if (w->invert & SND_SOC_DAPM_REGULATOR_BYPASS) {
ret = regulator_allow_bypass(w->regulator, false);
if (ret != 0)
dev_warn(w->dapm->dev,
"Failed to unbypass %s: %d\n",
w->name, ret);
}
return regulator_disable_deferred(w->regulator, w->shift); return regulator_disable_deferred(w->regulator, w->shift);
}
} }
EXPORT_SYMBOL_GPL(dapm_regulator_event); EXPORT_SYMBOL_GPL(dapm_regulator_event);
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/of.h>
#include <sound/soc.h> #include <sound/soc.h>
#include <sound/initval.h> #include <sound/initval.h>
...@@ -56,16 +57,47 @@ static struct snd_soc_card mop500_card = { ...@@ -56,16 +57,47 @@ static struct snd_soc_card mop500_card = {
.num_links = ARRAY_SIZE(mop500_dai_links), .num_links = ARRAY_SIZE(mop500_dai_links),
}; };
static int __devinit mop500_of_probe(struct platform_device *pdev,
struct device_node *np)
{
struct device_node *codec_np, *msp_np[2];
int i;
msp_np[0] = of_parse_phandle(np, "stericsson,cpu-dai", 0);
msp_np[1] = of_parse_phandle(np, "stericsson,cpu-dai", 1);
codec_np = of_parse_phandle(np, "stericsson,audio-codec", 0);
if (!(msp_np[0] && msp_np[1] && codec_np)) {
dev_err(&pdev->dev, "Phandle missing or invalid\n");
return -EINVAL;
}
for (i = 0; i < 2; i++) {
mop500_dai_links[i].cpu_of_node = msp_np[i];
mop500_dai_links[i].cpu_dai_name = NULL;
mop500_dai_links[i].codec_of_node = codec_np;
mop500_dai_links[i].codec_name = NULL;
}
snd_soc_of_parse_card_name(&mop500_card, "stericsson,card-name");
return 0;
}
static int __devinit mop500_probe(struct platform_device *pdev) static int __devinit mop500_probe(struct platform_device *pdev)
{ {
struct device_node *np = pdev->dev.of_node;
int ret; int ret;
pr_debug("%s: Enter.\n", __func__);
dev_dbg(&pdev->dev, "%s: Enter.\n", __func__); dev_dbg(&pdev->dev, "%s: Enter.\n", __func__);
mop500_card.dev = &pdev->dev; mop500_card.dev = &pdev->dev;
if (np) {
ret = mop500_of_probe(pdev, np);
if (ret)
return ret;
}
dev_dbg(&pdev->dev, "%s: Card %s: Set platform drvdata.\n", dev_dbg(&pdev->dev, "%s: Card %s: Set platform drvdata.\n",
__func__, mop500_card.name); __func__, mop500_card.name);
platform_set_drvdata(pdev, &mop500_card); platform_set_drvdata(pdev, &mop500_card);
...@@ -83,8 +115,7 @@ static int __devinit mop500_probe(struct platform_device *pdev) ...@@ -83,8 +115,7 @@ static int __devinit mop500_probe(struct platform_device *pdev)
ret = snd_soc_register_card(&mop500_card); ret = snd_soc_register_card(&mop500_card);
if (ret) if (ret)
dev_err(&pdev->dev, dev_err(&pdev->dev,
"Error: snd_soc_register_card failed (%d)!\n", "Error: snd_soc_register_card failed (%d)!\n", ret);
ret);
return ret; return ret;
} }
...@@ -97,14 +128,20 @@ static int __devexit mop500_remove(struct platform_device *pdev) ...@@ -97,14 +128,20 @@ static int __devexit mop500_remove(struct platform_device *pdev)
snd_soc_unregister_card(mop500_card); snd_soc_unregister_card(mop500_card);
mop500_ab8500_remove(mop500_card); mop500_ab8500_remove(mop500_card);
return 0; return 0;
} }
static const struct of_device_id snd_soc_mop500_match[] = {
{ .compatible = "stericsson,snd-soc-mop500", },
{},
};
static struct platform_driver snd_soc_mop500_driver = { static struct platform_driver snd_soc_mop500_driver = {
.driver = { .driver = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.name = "snd-soc-mop500", .name = "snd-soc-mop500",
.of_match_table = snd_soc_mop500_match,
}, },
.probe = mop500_probe, .probe = mop500_probe,
.remove = __devexit_p(mop500_remove), .remove = __devexit_p(mop500_remove),
......
...@@ -833,10 +833,16 @@ static int __devexit ux500_msp_drv_remove(struct platform_device *pdev) ...@@ -833,10 +833,16 @@ static int __devexit ux500_msp_drv_remove(struct platform_device *pdev)
return 0; return 0;
} }
static const struct of_device_id ux500_msp_i2s_match[] = {
{ .compatible = "stericsson,ux500-msp-i2s", },
{},
};
static struct platform_driver msp_i2s_driver = { static struct platform_driver msp_i2s_driver = {
.driver = { .driver = {
.name = "ux500-msp-i2s", .name = "ux500-msp-i2s",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.of_match_table = ux500_msp_i2s_match,
}, },
.probe = ux500_msp_drv_probe, .probe = ux500_msp_drv_probe,
.remove = ux500_msp_drv_remove, .remove = ux500_msp_drv_remove,
......
...@@ -15,8 +15,10 @@ ...@@ -15,8 +15,10 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pinctrl/consumer.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/of.h>
#include <mach/hardware.h> #include <mach/hardware.h>
#include <mach/msp.h> #include <mach/msp.h>
...@@ -25,6 +27,9 @@ ...@@ -25,6 +27,9 @@
#include "ux500_msp_i2s.h" #include "ux500_msp_i2s.h"
/* MSP1/3 Tx/Rx usage protection */
static DEFINE_SPINLOCK(msp_rxtx_lock);
/* Protocol desciptors */ /* Protocol desciptors */
static const struct msp_protdesc prot_descs[] = { static const struct msp_protdesc prot_descs[] = {
{ /* I2S */ { /* I2S */
...@@ -352,17 +357,23 @@ static int configure_multichannel(struct ux500_msp *msp, ...@@ -352,17 +357,23 @@ static int configure_multichannel(struct ux500_msp *msp,
static int enable_msp(struct ux500_msp *msp, struct ux500_msp_config *config) static int enable_msp(struct ux500_msp *msp, struct ux500_msp_config *config)
{ {
int status = 0; int status = 0, retval = 0;
u32 reg_val_DMACR, reg_val_GCR; u32 reg_val_DMACR, reg_val_GCR;
unsigned long flags;
/* Check msp state whether in RUN or CONFIGURED Mode */ /* Check msp state whether in RUN or CONFIGURED Mode */
if ((msp->msp_state == MSP_STATE_IDLE) && (msp->plat_init)) { if (msp->msp_state == MSP_STATE_IDLE) {
status = msp->plat_init(); spin_lock_irqsave(&msp_rxtx_lock, flags);
if (status) { if (msp->pinctrl_rxtx_ref == 0 &&
dev_err(msp->dev, "%s: ERROR: Failed to init MSP (%d)!\n", !(IS_ERR(msp->pinctrl_p) || IS_ERR(msp->pinctrl_def))) {
__func__, status); retval = pinctrl_select_state(msp->pinctrl_p,
return status; msp->pinctrl_def);
if (retval)
pr_err("could not set MSP defstate\n");
} }
if (!retval)
msp->pinctrl_rxtx_ref++;
spin_unlock_irqrestore(&msp_rxtx_lock, flags);
} }
/* Configure msp with protocol dependent settings */ /* Configure msp with protocol dependent settings */
...@@ -620,7 +631,8 @@ int ux500_msp_i2s_trigger(struct ux500_msp *msp, int cmd, int direction) ...@@ -620,7 +631,8 @@ int ux500_msp_i2s_trigger(struct ux500_msp *msp, int cmd, int direction)
int ux500_msp_i2s_close(struct ux500_msp *msp, unsigned int dir) int ux500_msp_i2s_close(struct ux500_msp *msp, unsigned int dir)
{ {
int status = 0; int status = 0, retval = 0;
unsigned long flags;
dev_dbg(msp->dev, "%s: Enter (dir = 0x%01x).\n", __func__, dir); dev_dbg(msp->dev, "%s: Enter (dir = 0x%01x).\n", __func__, dir);
...@@ -631,12 +643,19 @@ int ux500_msp_i2s_close(struct ux500_msp *msp, unsigned int dir) ...@@ -631,12 +643,19 @@ int ux500_msp_i2s_close(struct ux500_msp *msp, unsigned int dir)
writel((readl(msp->registers + MSP_GCR) & writel((readl(msp->registers + MSP_GCR) &
(~(FRAME_GEN_ENABLE | SRG_ENABLE))), (~(FRAME_GEN_ENABLE | SRG_ENABLE))),
msp->registers + MSP_GCR); msp->registers + MSP_GCR);
if (msp->plat_exit)
status = msp->plat_exit(); spin_lock_irqsave(&msp_rxtx_lock, flags);
if (status) WARN_ON(!msp->pinctrl_rxtx_ref);
dev_warn(msp->dev, msp->pinctrl_rxtx_ref--;
"%s: WARN: ux500_msp_i2s_exit failed (%d)!\n", if (msp->pinctrl_rxtx_ref == 0 &&
__func__, status); !(IS_ERR(msp->pinctrl_p) || IS_ERR(msp->pinctrl_sleep))) {
retval = pinctrl_select_state(msp->pinctrl_p,
msp->pinctrl_sleep);
if (retval)
pr_err("could not set MSP sleepstate\n");
}
spin_unlock_irqrestore(&msp_rxtx_lock, flags);
writel(0, msp->registers + MSP_GCR); writel(0, msp->registers + MSP_GCR);
writel(0, msp->registers + MSP_TCF); writel(0, msp->registers + MSP_TCF);
writel(0, msp->registers + MSP_RCF); writel(0, msp->registers + MSP_RCF);
...@@ -665,20 +684,33 @@ int ux500_msp_i2s_init_msp(struct platform_device *pdev, ...@@ -665,20 +684,33 @@ int ux500_msp_i2s_init_msp(struct platform_device *pdev,
{ {
struct resource *res = NULL; struct resource *res = NULL;
struct i2s_controller *i2s_cont; struct i2s_controller *i2s_cont;
struct device_node *np = pdev->dev.of_node;
struct ux500_msp *msp; struct ux500_msp *msp;
dev_dbg(&pdev->dev, "%s: Enter (name: %s, id: %d).\n", __func__,
pdev->name, platform_data->id);
*msp_p = devm_kzalloc(&pdev->dev, sizeof(struct ux500_msp), GFP_KERNEL); *msp_p = devm_kzalloc(&pdev->dev, sizeof(struct ux500_msp), GFP_KERNEL);
msp = *msp_p; msp = *msp_p;
if (!msp) if (!msp)
return -ENOMEM; return -ENOMEM;
if (np) {
if (!platform_data) {
platform_data = devm_kzalloc(&pdev->dev,
sizeof(struct msp_i2s_platform_data), GFP_KERNEL);
if (!platform_data)
ret = -ENOMEM;
}
} else
if (!platform_data)
ret = -EINVAL;
if (ret)
goto err_res;
dev_dbg(&pdev->dev, "%s: Enter (name: %s, id: %d).\n", __func__,
pdev->name, platform_data->id);
msp->id = platform_data->id; msp->id = platform_data->id;
msp->dev = &pdev->dev; msp->dev = &pdev->dev;
msp->plat_init = platform_data->msp_i2s_init;
msp->plat_exit = platform_data->msp_i2s_exit;
msp->dma_cfg_rx = platform_data->msp_i2s_dma_rx; msp->dma_cfg_rx = platform_data->msp_i2s_dma_rx;
msp->dma_cfg_tx = platform_data->msp_i2s_dma_tx; msp->dma_cfg_tx = platform_data->msp_i2s_dma_tx;
...@@ -715,6 +747,25 @@ int ux500_msp_i2s_init_msp(struct platform_device *pdev, ...@@ -715,6 +747,25 @@ int ux500_msp_i2s_init_msp(struct platform_device *pdev,
dev_dbg(&pdev->dev, "I2S device-name: '%s'\n", i2s_cont->name); dev_dbg(&pdev->dev, "I2S device-name: '%s'\n", i2s_cont->name);
msp->i2s_cont = i2s_cont; msp->i2s_cont = i2s_cont;
msp->pinctrl_p = pinctrl_get(msp->dev);
if (IS_ERR(msp->pinctrl_p))
dev_err(&pdev->dev, "could not get MSP pinctrl\n");
else {
msp->pinctrl_def = pinctrl_lookup_state(msp->pinctrl_p,
PINCTRL_STATE_DEFAULT);
if (IS_ERR(msp->pinctrl_def)) {
dev_err(&pdev->dev,
"could not get MSP defstate (%li)\n",
PTR_ERR(msp->pinctrl_def));
}
msp->pinctrl_sleep = pinctrl_lookup_state(msp->pinctrl_p,
PINCTRL_STATE_SLEEP);
if (IS_ERR(msp->pinctrl_sleep))
dev_err(&pdev->dev,
"could not get MSP idlestate (%li)\n",
PTR_ERR(msp->pinctrl_def));
}
return 0; return 0;
} }
......
...@@ -524,14 +524,18 @@ struct ux500_msp { ...@@ -524,14 +524,18 @@ struct ux500_msp {
struct dma_chan *rx_pipeid; struct dma_chan *rx_pipeid;
enum msp_state msp_state; enum msp_state msp_state;
int (*transfer) (struct ux500_msp *msp, struct i2s_message *message); int (*transfer) (struct ux500_msp *msp, struct i2s_message *message);
int (*plat_init) (void);
int (*plat_exit) (void);
struct timer_list notify_timer; struct timer_list notify_timer;
int def_elem_len; int def_elem_len;
unsigned int dir_busy; unsigned int dir_busy;
int loopback_enable; int loopback_enable;
u32 backup_regs[MAX_MSP_BACKUP_REGS]; u32 backup_regs[MAX_MSP_BACKUP_REGS];
unsigned int f_bitclk; unsigned int f_bitclk;
/* Pin modes */
struct pinctrl *pinctrl_p;
struct pinctrl_state *pinctrl_def;
struct pinctrl_state *pinctrl_sleep;
/* Reference Count */
int pinctrl_rxtx_ref;
}; };
struct ux500_msp_dma_params { struct ux500_msp_dma_params {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment