Commit 242f66c8 authored by Mark Brown's avatar Mark Brown

Merge remote-tracking branches 'asoc/topic/ac97', 'asoc/topic/ac97-mfd',...

Merge remote-tracking branches 'asoc/topic/ac97', 'asoc/topic/ac97-mfd', 'asoc/topic/amd' and 'asoc/topic/arizona-mfd' into asoc-next
......@@ -65,45 +65,6 @@ Optional properties:
a value that is out of range for a 16 bit register then the chip default
will be used. If present exactly five values must be specified.
- wlf,inmode : A list of INn_MODE register values, where n is the number
of input signals. Valid values are 0 (Differential), 1 (Single-ended) and
2 (Digital Microphone). If absent, INn_MODE registers set to 0 by default.
If present, values must be specified less than or equal to the number of
input signals. If values less than the number of input signals, elements
that have not been specified are set to 0 by default. Entries are:
<IN1, IN2, IN3, IN4> (wm5102, wm5110, wm8280, wm8997)
<IN1A, IN2A, IN1B, IN2B> (wm8998, wm1814)
- wlf,out-mono : A list of boolean values indicating whether each output is
mono or stereo. Position within the list indicates the output affected
(eg. First entry in the list corresponds to output 1). A non-zero value
indicates a mono output. If present, the number of values should be less
than or equal to the number of outputs, if less values are supplied the
additional outputs will be treated as stereo.
- wlf,dmic-ref : DMIC reference voltage source for each input, can be
selected from either MICVDD or one of the MICBIAS's, defines
(ARIZONA_DMIC_xxxx) are provided in <dt-bindings/mfd/arizona.txt>. If
present, the number of values should be less than or equal to the
number of inputs, unspecified inputs will use the chip default.
- wlf,max-channels-clocked : The maximum number of channels to be clocked on
each AIF, useful for I2S systems with multiple data lines being mastered.
Specify one cell for each AIF to be configured, specify zero for AIFs that
should be handled normally.
If present, number of cells must be less than or equal to the number of
AIFs. If less than the number of AIFs, for cells that have not been
specified the corresponding AIFs will be treated as default setting.
- wlf,spk-fmt : PDM speaker data format, must contain 2 cells (OUT5 and OUT6).
See the datasheet for values.
The second cell is ignored for codecs that do not have OUT6 (wm5102, wm8997,
wm8998, wm1814)
- wlf,spk-mute : PDM speaker mute setting, must contain 2 cells (OUT5 and OUT6).
See the datasheet for values.
The second cell is ignored for codecs that do not have OUT6 (wm5102, wm8997,
wm8998, wm1814)
- DCVDD-supply, MICVDD-supply : Power supplies, only need to be specified if
they are being externally supplied. As covered in
Documentation/devicetree/bindings/regulator/regulator.txt
......@@ -112,6 +73,7 @@ Optional properties:
Also see child specific device properties:
Regulator - ../regulator/arizona-regulator.txt
Extcon - ../extcon/extcon-arizona.txt
Sound - ../sound/arizona.txt
Example:
......
Cirrus Logic Arizona class audio SoCs
These devices are audio SoCs with extensive digital capabilities and a range
of analogue I/O.
This document lists sound specific bindings, see the primary binding
document:
../mfd/arizona.txt
Optional properties:
- wlf,inmode : A list of INn_MODE register values, where n is the number
of input signals. Valid values are 0 (Differential), 1 (Single-ended) and
2 (Digital Microphone). If absent, INn_MODE registers set to 0 by default.
If present, values must be specified less than or equal to the number of
input signals. If values less than the number of input signals, elements
that have not been specified are set to 0 by default. Entries are:
<IN1, IN2, IN3, IN4> (wm5102, wm5110, wm8280, wm8997)
<IN1A, IN2A, IN1B, IN2B> (wm8998, wm1814)
- wlf,out-mono : A list of boolean values indicating whether each output is
mono or stereo. Position within the list indicates the output affected
(eg. First entry in the list corresponds to output 1). A non-zero value
indicates a mono output. If present, the number of values should be less
than or equal to the number of outputs, if less values are supplied the
additional outputs will be treated as stereo.
- wlf,dmic-ref : DMIC reference voltage source for each input, can be
selected from either MICVDD or one of the MICBIAS's, defines
(ARIZONA_DMIC_xxxx) are provided in <dt-bindings/mfd/arizona.txt>. If
present, the number of values should be less than or equal to the
number of inputs, unspecified inputs will use the chip default.
- wlf,max-channels-clocked : The maximum number of channels to be clocked on
each AIF, useful for I2S systems with multiple data lines being mastered.
Specify one cell for each AIF to be configured, specify zero for AIFs that
should be handled normally.
If present, number of cells must be less than or equal to the number of
AIFs. If less than the number of AIFs, for cells that have not been
specified the corresponding AIFs will be treated as default setting.
- wlf,spk-fmt : PDM speaker data format, must contain 2 cells (OUT5 and OUT6).
See the datasheet for values.
The second cell is ignored for codecs that do not have OUT6 (wm5102, wm8997,
wm8998, wm1814)
- wlf,spk-mute : PDM speaker mute setting, must contain 2 cells (OUT5 and OUT6).
See the datasheet for values.
The second cell is ignored for codecs that do not have OUT6 (wm5102, wm8997,
wm8998, wm1814)
- wlf,out-volume-limit : The volume limit value that should be applied to each
output channel. See the datasheet for exact values. Channels are specified
in the order OUT1L, OUT1R, OUT2L, OUT2R, etc.
......@@ -14597,6 +14597,7 @@ F: Documentation/devicetree/bindings/extcon/extcon-arizona.txt
F: Documentation/devicetree/bindings/regulator/arizona-regulator.txt
F: Documentation/devicetree/bindings/mfd/arizona.txt
F: Documentation/devicetree/bindings/mfd/wm831x.txt
F: Documentation/devicetree/bindings/sound/wlf,arizona.txt
F: arch/arm/mach-s3c64xx/mach-crag6410*
F: drivers/clk/clk-wm83*.c
F: drivers/extcon/extcon-arizona.c
......
......@@ -371,6 +371,8 @@ static int acp_hw_init(void *handle)
adev->acp.acp_cell[0].name = "acp_audio_dma";
adev->acp.acp_cell[0].num_resources = 4;
adev->acp.acp_cell[0].resources = &adev->acp.acp_res[0];
adev->acp.acp_cell[0].platform_data = &adev->asic_type;
adev->acp.acp_cell[0].pdata_size = sizeof(adev->asic_type);
adev->acp.acp_cell[1].name = "designware-i2s";
adev->acp.acp_cell[1].num_resources = 1;
......
......@@ -23,34 +23,9 @@
#ifndef __AMD_SHARED_H__
#define __AMD_SHARED_H__
#define AMD_MAX_USEC_TIMEOUT 200000 /* 200 ms */
#include <drm/amd_asic_type.h>
/*
* Supported ASIC types
*/
enum amd_asic_type {
CHIP_TAHITI = 0,
CHIP_PITCAIRN,
CHIP_VERDE,
CHIP_OLAND,
CHIP_HAINAN,
CHIP_BONAIRE,
CHIP_KAVERI,
CHIP_KABINI,
CHIP_HAWAII,
CHIP_MULLINS,
CHIP_TOPAZ,
CHIP_TONGA,
CHIP_FIJI,
CHIP_CARRIZO,
CHIP_STONEY,
CHIP_POLARIS10,
CHIP_POLARIS11,
CHIP_POLARIS12,
CHIP_VEGA10,
CHIP_RAVEN,
CHIP_LAST,
};
#define AMD_MAX_USEC_TIMEOUT 200000 /* 200 ms */
/*
* Chip flags
......
......@@ -727,7 +727,7 @@ config TOUCHSCREEN_WM831X
config TOUCHSCREEN_WM97XX
tristate "Support for WM97xx AC97 touchscreen controllers"
depends on AC97_BUS
depends on AC97_BUS || AC97_BUS_NEW
help
Say Y here if you have a Wolfson Microelectronics WM97xx
touchscreen connected to your system. Note that this option
......
......@@ -44,6 +44,7 @@
#include <linux/pm.h>
#include <linux/interrupt.h>
#include <linux/bitops.h>
#include <linux/mfd/wm97xx.h>
#include <linux/workqueue.h>
#include <linux/wm97xx.h>
#include <linux/uaccess.h>
......@@ -581,27 +582,85 @@ static void wm97xx_ts_input_close(struct input_dev *idev)
wm->codec->acc_enable(wm, 0);
}
static int wm97xx_probe(struct device *dev)
static int wm97xx_register_touch(struct wm97xx *wm)
{
struct wm97xx *wm;
struct wm97xx_pdata *pdata = dev_get_platdata(dev);
int ret = 0, id = 0;
struct wm97xx_pdata *pdata = dev_get_platdata(wm->dev);
int ret;
wm = kzalloc(sizeof(struct wm97xx), GFP_KERNEL);
if (!wm)
wm->input_dev = devm_input_allocate_device(wm->dev);
if (wm->input_dev == NULL)
return -ENOMEM;
mutex_init(&wm->codec_mutex);
wm->dev = dev;
dev_set_drvdata(dev, wm);
wm->ac97 = to_ac97_t(dev);
/* set up touch configuration */
wm->input_dev->name = "wm97xx touchscreen";
wm->input_dev->phys = "wm97xx";
wm->input_dev->open = wm97xx_ts_input_open;
wm->input_dev->close = wm97xx_ts_input_close;
__set_bit(EV_ABS, wm->input_dev->evbit);
__set_bit(EV_KEY, wm->input_dev->evbit);
__set_bit(BTN_TOUCH, wm->input_dev->keybit);
input_set_abs_params(wm->input_dev, ABS_X, abs_x[0], abs_x[1],
abs_x[2], 0);
input_set_abs_params(wm->input_dev, ABS_Y, abs_y[0], abs_y[1],
abs_y[2], 0);
input_set_abs_params(wm->input_dev, ABS_PRESSURE, abs_p[0], abs_p[1],
abs_p[2], 0);
input_set_drvdata(wm->input_dev, wm);
wm->input_dev->dev.parent = wm->dev;
ret = input_register_device(wm->input_dev);
if (ret)
return ret;
/*
* register our extended touch device (for machine specific
* extensions)
*/
wm->touch_dev = platform_device_alloc("wm97xx-touch", -1);
if (!wm->touch_dev) {
ret = -ENOMEM;
goto touch_err;
}
platform_set_drvdata(wm->touch_dev, wm);
wm->touch_dev->dev.parent = wm->dev;
wm->touch_dev->dev.platform_data = pdata;
ret = platform_device_add(wm->touch_dev);
if (ret < 0)
goto touch_reg_err;
return 0;
touch_reg_err:
platform_device_put(wm->touch_dev);
touch_err:
input_unregister_device(wm->input_dev);
wm->input_dev = NULL;
return ret;
}
static void wm97xx_unregister_touch(struct wm97xx *wm)
{
platform_device_unregister(wm->touch_dev);
input_unregister_device(wm->input_dev);
wm->input_dev = NULL;
}
static int _wm97xx_probe(struct wm97xx *wm)
{
int id = 0;
mutex_init(&wm->codec_mutex);
dev_set_drvdata(wm->dev, wm);
/* check that we have a supported codec */
id = wm97xx_reg_read(wm, AC97_VENDOR_ID1);
if (id != WM97XX_ID1) {
dev_err(dev, "Device with vendor %04x is not a wm97xx\n", id);
ret = -ENODEV;
goto alloc_err;
dev_err(wm->dev,
"Device with vendor %04x is not a wm97xx\n", id);
return -ENODEV;
}
wm->id = wm97xx_reg_read(wm, AC97_VENDOR_ID2);
......@@ -629,8 +688,7 @@ static int wm97xx_probe(struct device *dev)
default:
dev_err(wm->dev, "Support for wm97%02x not compiled in.\n",
wm->id & 0xff);
ret = -ENODEV;
goto alloc_err;
return -ENODEV;
}
/* set up physical characteristics */
......@@ -644,79 +702,58 @@ static int wm97xx_probe(struct device *dev)
wm->gpio[4] = wm97xx_reg_read(wm, AC97_GPIO_STATUS);
wm->gpio[5] = wm97xx_reg_read(wm, AC97_MISC_AFE);
wm->input_dev = input_allocate_device();
if (wm->input_dev == NULL) {
ret = -ENOMEM;
goto alloc_err;
}
/* set up touch configuration */
wm->input_dev->name = "wm97xx touchscreen";
wm->input_dev->phys = "wm97xx";
wm->input_dev->open = wm97xx_ts_input_open;
wm->input_dev->close = wm97xx_ts_input_close;
__set_bit(EV_ABS, wm->input_dev->evbit);
__set_bit(EV_KEY, wm->input_dev->evbit);
__set_bit(BTN_TOUCH, wm->input_dev->keybit);
input_set_abs_params(wm->input_dev, ABS_X, abs_x[0], abs_x[1],
abs_x[2], 0);
input_set_abs_params(wm->input_dev, ABS_Y, abs_y[0], abs_y[1],
abs_y[2], 0);
input_set_abs_params(wm->input_dev, ABS_PRESSURE, abs_p[0], abs_p[1],
abs_p[2], 0);
return wm97xx_register_touch(wm);
}
input_set_drvdata(wm->input_dev, wm);
wm->input_dev->dev.parent = dev;
static void wm97xx_remove_battery(struct wm97xx *wm)
{
platform_device_unregister(wm->battery_dev);
}
ret = input_register_device(wm->input_dev);
if (ret < 0)
goto dev_alloc_err;
static int wm97xx_add_battery(struct wm97xx *wm,
struct wm97xx_batt_pdata *pdata)
{
int ret;
/* register our battery device */
wm->battery_dev = platform_device_alloc("wm97xx-battery", -1);
if (!wm->battery_dev) {
ret = -ENOMEM;
goto batt_err;
}
if (!wm->battery_dev)
return -ENOMEM;
platform_set_drvdata(wm->battery_dev, wm);
wm->battery_dev->dev.parent = dev;
wm->battery_dev->dev.platform_data = pdata ? pdata->batt_pdata : NULL;
wm->battery_dev->dev.parent = wm->dev;
wm->battery_dev->dev.platform_data = pdata;
ret = platform_device_add(wm->battery_dev);
if (ret < 0)
goto batt_reg_err;
if (ret)
platform_device_put(wm->battery_dev);
/* register our extended touch device (for machine specific
* extensions) */
wm->touch_dev = platform_device_alloc("wm97xx-touch", -1);
if (!wm->touch_dev) {
ret = -ENOMEM;
goto touch_err;
}
platform_set_drvdata(wm->touch_dev, wm);
wm->touch_dev->dev.parent = dev;
wm->touch_dev->dev.platform_data = pdata;
ret = platform_device_add(wm->touch_dev);
return ret;
}
static int wm97xx_probe(struct device *dev)
{
struct wm97xx *wm;
int ret;
struct wm97xx_pdata *pdata = dev_get_platdata(dev);
wm = devm_kzalloc(dev, sizeof(struct wm97xx), GFP_KERNEL);
if (!wm)
return -ENOMEM;
wm->dev = dev;
wm->ac97 = to_ac97_t(dev);
ret = _wm97xx_probe(wm);
if (ret)
return ret;
ret = wm97xx_add_battery(wm, pdata ? pdata->batt_pdata : NULL);
if (ret < 0)
goto touch_reg_err;
goto batt_err;
return ret;
touch_reg_err:
platform_device_put(wm->touch_dev);
touch_err:
platform_device_del(wm->battery_dev);
batt_reg_err:
platform_device_put(wm->battery_dev);
batt_err:
input_unregister_device(wm->input_dev);
wm->input_dev = NULL;
dev_alloc_err:
input_free_device(wm->input_dev);
alloc_err:
kfree(wm);
batt_err:
wm97xx_unregister_touch(wm);
return ret;
}
......@@ -724,14 +761,45 @@ static int wm97xx_remove(struct device *dev)
{
struct wm97xx *wm = dev_get_drvdata(dev);
platform_device_unregister(wm->battery_dev);
platform_device_unregister(wm->touch_dev);
input_unregister_device(wm->input_dev);
kfree(wm);
wm97xx_remove_battery(wm);
wm97xx_unregister_touch(wm);
return 0;
}
static int wm97xx_mfd_probe(struct platform_device *pdev)
{
struct wm97xx *wm;
struct wm97xx_platform_data *mfd_pdata = dev_get_platdata(&pdev->dev);
int ret;
wm = devm_kzalloc(&pdev->dev, sizeof(struct wm97xx), GFP_KERNEL);
if (!wm)
return -ENOMEM;
wm->dev = &pdev->dev;
wm->ac97 = mfd_pdata->ac97;
ret = _wm97xx_probe(wm);
if (ret)
return ret;
ret = wm97xx_add_battery(wm, mfd_pdata->batt_pdata);
if (ret < 0)
goto batt_err;
return ret;
batt_err:
wm97xx_unregister_touch(wm);
return ret;
}
static int wm97xx_mfd_remove(struct platform_device *pdev)
{
return wm97xx_remove(&pdev->dev);
}
static int __maybe_unused wm97xx_suspend(struct device *dev)
{
struct wm97xx *wm = dev_get_drvdata(dev);
......@@ -828,21 +896,41 @@ EXPORT_SYMBOL_GPL(wm97xx_unregister_mach_ops);
static struct device_driver wm97xx_driver = {
.name = "wm97xx-ts",
#ifdef CONFIG_AC97_BUS
.bus = &ac97_bus_type,
#endif
.owner = THIS_MODULE,
.probe = wm97xx_probe,
.remove = wm97xx_remove,
.pm = &wm97xx_pm_ops,
};
static struct platform_driver wm97xx_mfd_driver = {
.driver = {
.name = "wm97xx-ts",
.pm = &wm97xx_pm_ops,
},
.probe = wm97xx_mfd_probe,
.remove = wm97xx_mfd_remove,
};
static int __init wm97xx_init(void)
{
return driver_register(&wm97xx_driver);
int ret;
ret = platform_driver_register(&wm97xx_mfd_driver);
if (ret)
return ret;
if (IS_BUILTIN(CONFIG_AC97_BUS))
ret = driver_register(&wm97xx_driver);
return ret;
}
static void __exit wm97xx_exit(void)
{
driver_unregister(&wm97xx_driver);
platform_driver_unregister(&wm97xx_mfd_driver);
}
module_init(wm97xx_init);
......
......@@ -1746,6 +1746,20 @@ config MFD_WM8994
core support for the WM8994, in order to use the actual
functionaltiy of the device other drivers must be enabled.
config MFD_WM97xx
tristate "Wolfson Microelectronics WM97xx"
select MFD_CORE
select REGMAP_AC97
select AC97_BUS_COMPAT
depends on AC97_BUS_NEW
help
The WM9705, WM9712 and WM9713 is a highly integrated hi-fi CODEC
designed for smartphone applications. As well as audio functionality
it has on board GPIO and a touchscreen functionality which is
supported via the relevant subsystems. This driver provides core
support for the WM97xx, in order to use the actual functionaltiy of
the device other drivers must be enabled.
config MFD_STW481X
tristate "Support for ST Microelectronics STw481x"
depends on I2C && (ARCH_NOMADIK || COMPILE_TEST)
......
......@@ -74,6 +74,7 @@ obj-$(CONFIG_MFD_WM8350) += wm8350.o
obj-$(CONFIG_MFD_WM8350_I2C) += wm8350-i2c.o
wm8994-objs := wm8994-core.o wm8994-irq.o wm8994-regmap.o
obj-$(CONFIG_MFD_WM8994) += wm8994.o
obj-$(CONFIG_MFD_WM97xx) += wm97xx-core.o
obj-$(CONFIG_TPS6105X) += tps6105x.o
obj-$(CONFIG_TPS65010) += tps65010.o
......
......@@ -797,12 +797,7 @@ EXPORT_SYMBOL_GPL(arizona_of_get_type);
static int arizona_of_get_core_pdata(struct arizona *arizona)
{
struct arizona_pdata *pdata = &arizona->pdata;
struct property *prop;
const __be32 *cur;
u32 val;
u32 pdm_val[ARIZONA_MAX_PDM_SPK];
int ret, i;
int count = 0;
pdata->reset = of_get_named_gpio(arizona->dev->of_node, "wlf,reset", 0);
if (pdata->reset == -EPROBE_DEFER) {
......@@ -836,64 +831,6 @@ static int arizona_of_get_core_pdata(struct arizona *arizona)
ret);
}
of_property_for_each_u32(arizona->dev->of_node, "wlf,inmode", prop,
cur, val) {
if (count == ARRAY_SIZE(pdata->inmode))
break;
pdata->inmode[count] = val;
count++;
}
count = 0;
of_property_for_each_u32(arizona->dev->of_node, "wlf,dmic-ref", prop,
cur, val) {
if (count == ARRAY_SIZE(pdata->dmic_ref))
break;
pdata->dmic_ref[count] = val;
count++;
}
count = 0;
of_property_for_each_u32(arizona->dev->of_node, "wlf,out-mono", prop,
cur, val) {
if (count == ARRAY_SIZE(pdata->out_mono))
break;
pdata->out_mono[count] = !!val;
count++;
}
count = 0;
of_property_for_each_u32(arizona->dev->of_node,
"wlf,max-channels-clocked",
prop, cur, val) {
if (count == ARRAY_SIZE(pdata->max_channels_clocked))
break;
pdata->max_channels_clocked[count] = val;
count++;
}
ret = of_property_read_u32_array(arizona->dev->of_node,
"wlf,spk-fmt",
pdm_val,
ARRAY_SIZE(pdm_val));
if (ret >= 0)
for (count = 0; count < ARRAY_SIZE(pdata->spk_fmt); ++count)
pdata->spk_fmt[count] = pdm_val[count];
ret = of_property_read_u32_array(arizona->dev->of_node,
"wlf,spk-mute",
pdm_val,
ARRAY_SIZE(pdm_val));
if (ret >= 0)
for (count = 0; count < ARRAY_SIZE(pdata->spk_mute); ++count)
pdata->spk_mute[count] = pdm_val[count];
return 0;
}
......@@ -1026,7 +963,7 @@ int arizona_dev_init(struct arizona *arizona)
const char * const mclk_name[] = { "mclk1", "mclk2" };
struct device *dev = arizona->dev;
const char *type_name = NULL;
unsigned int reg, val, mask;
unsigned int reg, val;
int (*apply_patch)(struct arizona *) = NULL;
const struct mfd_cell *subdevs = NULL;
int n_subdevs, ret, i;
......@@ -1429,73 +1366,6 @@ int arizona_dev_init(struct arizona *arizona)
ARIZONA_MICB1_RATE, val);
}
for (i = 0; i < ARIZONA_MAX_INPUT; i++) {
/* Default for both is 0 so noop with defaults */
val = arizona->pdata.dmic_ref[i]
<< ARIZONA_IN1_DMIC_SUP_SHIFT;
if (arizona->pdata.inmode[i] & ARIZONA_INMODE_DMIC)
val |= 1 << ARIZONA_IN1_MODE_SHIFT;
switch (arizona->type) {
case WM8998:
case WM1814:
regmap_update_bits(arizona->regmap,
ARIZONA_ADC_DIGITAL_VOLUME_1L + (i * 8),
ARIZONA_IN1L_SRC_SE_MASK,
(arizona->pdata.inmode[i] & ARIZONA_INMODE_SE)
<< ARIZONA_IN1L_SRC_SE_SHIFT);
regmap_update_bits(arizona->regmap,
ARIZONA_ADC_DIGITAL_VOLUME_1R + (i * 8),
ARIZONA_IN1R_SRC_SE_MASK,
(arizona->pdata.inmode[i] & ARIZONA_INMODE_SE)
<< ARIZONA_IN1R_SRC_SE_SHIFT);
mask = ARIZONA_IN1_DMIC_SUP_MASK |
ARIZONA_IN1_MODE_MASK;
break;
default:
if (arizona->pdata.inmode[i] & ARIZONA_INMODE_SE)
val |= 1 << ARIZONA_IN1_SINGLE_ENDED_SHIFT;
mask = ARIZONA_IN1_DMIC_SUP_MASK |
ARIZONA_IN1_MODE_MASK |
ARIZONA_IN1_SINGLE_ENDED_MASK;
break;
}
regmap_update_bits(arizona->regmap,
ARIZONA_IN1L_CONTROL + (i * 8),
mask, val);
}
for (i = 0; i < ARIZONA_MAX_OUTPUT; i++) {
/* Default is 0 so noop with defaults */
if (arizona->pdata.out_mono[i])
val = ARIZONA_OUT1_MONO;
else
val = 0;
regmap_update_bits(arizona->regmap,
ARIZONA_OUTPUT_PATH_CONFIG_1L + (i * 8),
ARIZONA_OUT1_MONO, val);
}
for (i = 0; i < ARIZONA_MAX_PDM_SPK; i++) {
if (arizona->pdata.spk_mute[i])
regmap_update_bits(arizona->regmap,
ARIZONA_PDM_SPK1_CTRL_1 + (i * 2),
ARIZONA_SPK1_MUTE_ENDIAN_MASK |
ARIZONA_SPK1_MUTE_SEQ1_MASK,
arizona->pdata.spk_mute[i]);
if (arizona->pdata.spk_fmt[i])
regmap_update_bits(arizona->regmap,
ARIZONA_PDM_SPK1_CTRL_2 + (i * 2),
ARIZONA_SPK1_FMT_MASK,
arizona->pdata.spk_fmt[i]);
}
pm_runtime_set_active(arizona->dev);
pm_runtime_enable(arizona->dev);
......
/*
* Wolfson WM97xx -- Core device
*
* Copyright (C) 2017 Robert Jarzmik
*
* 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.
*
* Features:
* - an AC97 audio codec
* - a touchscreen driver
* - a GPIO block
*/
#include <linux/device.h>
#include <linux/mfd/core.h>
#include <linux/mfd/wm97xx.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/wm97xx.h>
#include <sound/ac97/codec.h>
#include <sound/ac97/compat.h>
#define WM9705_VENDOR_ID 0x574d4c05
#define WM9712_VENDOR_ID 0x574d4c12
#define WM9713_VENDOR_ID 0x574d4c13
#define WM97xx_VENDOR_ID_MASK 0xffffffff
struct wm97xx_priv {
struct regmap *regmap;
struct snd_ac97 *ac97;
struct device *dev;
struct wm97xx_platform_data codec_pdata;
};
static bool wm97xx_readable_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case AC97_RESET ... AC97_PCM_SURR_DAC_RATE:
case AC97_PCM_LR_ADC_RATE:
case AC97_CENTER_LFE_MASTER:
case AC97_SPDIF ... AC97_LINE1_LEVEL:
case AC97_GPIO_CFG ... 0x5c:
case AC97_CODEC_CLASS_REV ... AC97_PCI_SID:
case 0x74 ... AC97_VENDOR_ID2:
return true;
default:
return false;
}
}
static bool wm97xx_writeable_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case AC97_VENDOR_ID1:
case AC97_VENDOR_ID2:
return false;
default:
return wm97xx_readable_reg(dev, reg);
}
}
static const struct reg_default wm9705_reg_defaults[] = {
{ 0x02, 0x8000 },
{ 0x04, 0x8000 },
{ 0x06, 0x8000 },
{ 0x0a, 0x8000 },
{ 0x0c, 0x8008 },
{ 0x0e, 0x8008 },
{ 0x10, 0x8808 },
{ 0x12, 0x8808 },
{ 0x14, 0x8808 },
{ 0x16, 0x8808 },
{ 0x18, 0x8808 },
{ 0x1a, 0x0000 },
{ 0x1c, 0x8000 },
{ 0x20, 0x0000 },
{ 0x22, 0x0000 },
{ 0x26, 0x000f },
{ 0x28, 0x0605 },
{ 0x2a, 0x0000 },
{ 0x2c, 0xbb80 },
{ 0x32, 0xbb80 },
{ 0x34, 0x2000 },
{ 0x5a, 0x0000 },
{ 0x5c, 0x0000 },
{ 0x72, 0x0808 },
{ 0x74, 0x0000 },
{ 0x76, 0x0006 },
{ 0x78, 0x0000 },
{ 0x7a, 0x0000 },
};
static const struct regmap_config wm9705_regmap_config = {
.reg_bits = 16,
.reg_stride = 2,
.val_bits = 16,
.max_register = 0x7e,
.cache_type = REGCACHE_RBTREE,
.reg_defaults = wm9705_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(wm9705_reg_defaults),
.volatile_reg = regmap_ac97_default_volatile,
.readable_reg = wm97xx_readable_reg,
.writeable_reg = wm97xx_writeable_reg,
};
static struct mfd_cell wm9705_cells[] = {
{ .name = "wm9705-codec", },
{ .name = "wm97xx-ts", },
};
static bool wm9712_volatile_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case AC97_REC_GAIN:
return true;
default:
return regmap_ac97_default_volatile(dev, reg);
}
}
static const struct reg_default wm9712_reg_defaults[] = {
{ 0x02, 0x8000 },
{ 0x04, 0x8000 },
{ 0x06, 0x8000 },
{ 0x08, 0x0f0f },
{ 0x0a, 0xaaa0 },
{ 0x0c, 0xc008 },
{ 0x0e, 0x6808 },
{ 0x10, 0xe808 },
{ 0x12, 0xaaa0 },
{ 0x14, 0xad00 },
{ 0x16, 0x8000 },
{ 0x18, 0xe808 },
{ 0x1a, 0x3000 },
{ 0x1c, 0x8000 },
{ 0x20, 0x0000 },
{ 0x22, 0x0000 },
{ 0x26, 0x000f },
{ 0x28, 0x0605 },
{ 0x2a, 0x0410 },
{ 0x2c, 0xbb80 },
{ 0x2e, 0xbb80 },
{ 0x32, 0xbb80 },
{ 0x34, 0x2000 },
{ 0x4c, 0xf83e },
{ 0x4e, 0xffff },
{ 0x50, 0x0000 },
{ 0x52, 0x0000 },
{ 0x56, 0xf83e },
{ 0x58, 0x0008 },
{ 0x5c, 0x0000 },
{ 0x60, 0xb032 },
{ 0x62, 0x3e00 },
{ 0x64, 0x0000 },
{ 0x76, 0x0006 },
{ 0x78, 0x0001 },
{ 0x7a, 0x0000 },
};
static const struct regmap_config wm9712_regmap_config = {
.reg_bits = 16,
.reg_stride = 2,
.val_bits = 16,
.max_register = 0x7e,
.cache_type = REGCACHE_RBTREE,
.reg_defaults = wm9712_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(wm9712_reg_defaults),
.volatile_reg = wm9712_volatile_reg,
.readable_reg = wm97xx_readable_reg,
.writeable_reg = wm97xx_writeable_reg,
};
static struct mfd_cell wm9712_cells[] = {
{ .name = "wm9712-codec", },
{ .name = "wm97xx-ts", },
};
static const struct reg_default wm9713_reg_defaults[] = {
{ 0x02, 0x8080 }, /* Speaker Output Volume */
{ 0x04, 0x8080 }, /* Headphone Output Volume */
{ 0x06, 0x8080 }, /* Out3/OUT4 Volume */
{ 0x08, 0xc880 }, /* Mono Volume */
{ 0x0a, 0xe808 }, /* LINEIN Volume */
{ 0x0c, 0xe808 }, /* DAC PGA Volume */
{ 0x0e, 0x0808 }, /* MIC PGA Volume */
{ 0x10, 0x00da }, /* MIC Routing Control */
{ 0x12, 0x8000 }, /* Record PGA Volume */
{ 0x14, 0xd600 }, /* Record Routing */
{ 0x16, 0xaaa0 }, /* PCBEEP Volume */
{ 0x18, 0xaaa0 }, /* VxDAC Volume */
{ 0x1a, 0xaaa0 }, /* AUXDAC Volume */
{ 0x1c, 0x0000 }, /* Output PGA Mux */
{ 0x1e, 0x0000 }, /* DAC 3D control */
{ 0x20, 0x0f0f }, /* DAC Tone Control*/
{ 0x22, 0x0040 }, /* MIC Input Select & Bias */
{ 0x24, 0x0000 }, /* Output Volume Mapping & Jack */
{ 0x26, 0x7f00 }, /* Powerdown Ctrl/Stat*/
{ 0x28, 0x0405 }, /* Extended Audio ID */
{ 0x2a, 0x0410 }, /* Extended Audio Start/Ctrl */
{ 0x2c, 0xbb80 }, /* Audio DACs Sample Rate */
{ 0x2e, 0xbb80 }, /* AUXDAC Sample Rate */
{ 0x32, 0xbb80 }, /* Audio ADCs Sample Rate */
{ 0x36, 0x4523 }, /* PCM codec control */
{ 0x3a, 0x2000 }, /* SPDIF control */
{ 0x3c, 0xfdff }, /* Powerdown 1 */
{ 0x3e, 0xffff }, /* Powerdown 2 */
{ 0x40, 0x0000 }, /* General Purpose */
{ 0x42, 0x0000 }, /* Fast Power-Up Control */
{ 0x44, 0x0080 }, /* MCLK/PLL Control */
{ 0x46, 0x0000 }, /* MCLK/PLL Control */
{ 0x4c, 0xfffe }, /* GPIO Pin Configuration */
{ 0x4e, 0xffff }, /* GPIO Pin Polarity / Type */
{ 0x50, 0x0000 }, /* GPIO Pin Sticky */
{ 0x52, 0x0000 }, /* GPIO Pin Wake-Up */
/* GPIO Pin Status */
{ 0x56, 0xfffe }, /* GPIO Pin Sharing */
{ 0x58, 0x4000 }, /* GPIO PullUp/PullDown */
{ 0x5a, 0x0000 }, /* Additional Functions 1 */
{ 0x5c, 0x0000 }, /* Additional Functions 2 */
{ 0x60, 0xb032 }, /* ALC Control */
{ 0x62, 0x3e00 }, /* ALC / Noise Gate Control */
{ 0x64, 0x0000 }, /* AUXDAC input control */
{ 0x74, 0x0000 }, /* Digitiser Reg 1 */
{ 0x76, 0x0006 }, /* Digitiser Reg 2 */
{ 0x78, 0x0001 }, /* Digitiser Reg 3 */
{ 0x7a, 0x0000 }, /* Digitiser Read Back */
};
static const struct regmap_config wm9713_regmap_config = {
.reg_bits = 16,
.reg_stride = 2,
.val_bits = 16,
.max_register = 0x7e,
.cache_type = REGCACHE_RBTREE,
.reg_defaults = wm9713_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(wm9713_reg_defaults),
.volatile_reg = regmap_ac97_default_volatile,
.readable_reg = wm97xx_readable_reg,
.writeable_reg = wm97xx_writeable_reg,
};
static struct mfd_cell wm9713_cells[] = {
{ .name = "wm9713-codec", },
{ .name = "wm97xx-ts", },
};
static int wm97xx_ac97_probe(struct ac97_codec_device *adev)
{
struct wm97xx_priv *wm97xx;
const struct regmap_config *config;
struct wm97xx_platform_data *codec_pdata;
struct mfd_cell *cells;
int ret = -ENODEV, nb_cells, i;
struct wm97xx_pdata *pdata = snd_ac97_codec_get_platdata(adev);
wm97xx = devm_kzalloc(ac97_codec_dev2dev(adev),
sizeof(*wm97xx), GFP_KERNEL);
if (!wm97xx)
return -ENOMEM;
wm97xx->dev = ac97_codec_dev2dev(adev);
wm97xx->ac97 = snd_ac97_compat_alloc(adev);
if (IS_ERR(wm97xx->ac97))
return PTR_ERR(wm97xx->ac97);
ac97_set_drvdata(adev, wm97xx);
dev_info(wm97xx->dev, "wm97xx core found, id=0x%x\n",
adev->vendor_id);
codec_pdata = &wm97xx->codec_pdata;
codec_pdata->ac97 = wm97xx->ac97;
codec_pdata->batt_pdata = pdata->batt_pdata;
switch (adev->vendor_id) {
case WM9705_VENDOR_ID:
config = &wm9705_regmap_config;
cells = wm9705_cells;
nb_cells = ARRAY_SIZE(wm9705_cells);
break;
case WM9712_VENDOR_ID:
config = &wm9712_regmap_config;
cells = wm9712_cells;
nb_cells = ARRAY_SIZE(wm9712_cells);
break;
case WM9713_VENDOR_ID:
config = &wm9713_regmap_config;
cells = wm9713_cells;
nb_cells = ARRAY_SIZE(wm9713_cells);
break;
default:
goto err_free_compat;
}
for (i = 0; i < nb_cells; i++) {
cells[i].platform_data = codec_pdata;
cells[i].pdata_size = sizeof(*codec_pdata);
}
codec_pdata->regmap = devm_regmap_init_ac97(wm97xx->ac97, config);
if (IS_ERR(codec_pdata->regmap)) {
ret = PTR_ERR(codec_pdata->regmap);
goto err_free_compat;
}
ret = devm_mfd_add_devices(wm97xx->dev, PLATFORM_DEVID_NONE,
cells, nb_cells, NULL, 0, NULL);
if (ret)
goto err_free_compat;
return ret;
err_free_compat:
snd_ac97_compat_release(wm97xx->ac97);
return ret;
}
static int wm97xx_ac97_remove(struct ac97_codec_device *adev)
{
struct wm97xx_priv *wm97xx = ac97_get_drvdata(adev);
snd_ac97_compat_release(wm97xx->ac97);
return 0;
}
static const struct ac97_id wm97xx_ac97_ids[] = {
{ .id = WM9705_VENDOR_ID, .mask = WM97xx_VENDOR_ID_MASK },
{ .id = WM9712_VENDOR_ID, .mask = WM97xx_VENDOR_ID_MASK },
{ .id = WM9713_VENDOR_ID, .mask = WM97xx_VENDOR_ID_MASK },
{ }
};
static struct ac97_codec_driver wm97xx_ac97_driver = {
.driver = {
.name = "wm97xx-core",
},
.probe = wm97xx_ac97_probe,
.remove = wm97xx_ac97_remove,
.id_table = wm97xx_ac97_ids,
};
static int __init wm97xx_module_init(void)
{
return snd_ac97_codec_driver_register(&wm97xx_ac97_driver);
}
module_init(wm97xx_module_init);
static void __exit wm97xx_module_exit(void)
{
snd_ac97_codec_driver_unregister(&wm97xx_ac97_driver);
}
module_exit(wm97xx_module_exit);
MODULE_DESCRIPTION("WM9712, WM9713 core driver");
MODULE_AUTHOR("Robert Jarzmik <robert.jarzmik@free.fr>");
MODULE_LICENSE("GPL");
/*
* Copyright 2017 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef __AMD_ASIC_TYPE_H__
#define __AMD_ASIC_TYPE_H__
/*
* Supported ASIC types
*/
enum amd_asic_type {
CHIP_TAHITI = 0,
CHIP_PITCAIRN,
CHIP_VERDE,
CHIP_OLAND,
CHIP_HAINAN,
CHIP_BONAIRE,
CHIP_KAVERI,
CHIP_KABINI,
CHIP_HAWAII,
CHIP_MULLINS,
CHIP_TOPAZ,
CHIP_TONGA,
CHIP_FIJI,
CHIP_CARRIZO,
CHIP_STONEY,
CHIP_POLARIS10,
CHIP_POLARIS11,
CHIP_POLARIS12,
CHIP_VEGA10,
CHIP_RAVEN,
CHIP_LAST,
};
#endif /*__AMD_ASIC_TYPE_H__ */
......@@ -174,6 +174,9 @@ struct arizona_pdata {
/** Mode for outputs */
int out_mono[ARIZONA_MAX_OUTPUT];
/** Limit output volumes */
unsigned int out_vol_limit[2 * ARIZONA_MAX_OUTPUT];
/** PDM speaker mute setting */
unsigned int spk_mute[ARIZONA_MAX_PDM_SPK];
......
/*
* wm97xx client interface
*
* Copyright (C) 2017 Robert Jarzmik
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#ifndef __LINUX_MFD_WM97XX_H
#define __LINUX_MFD_WM97XX_H
struct regmap;
struct wm97xx_batt_pdata;
struct snd_ac97;
struct wm97xx_platform_data {
struct snd_ac97 *ac97;
struct regmap *regmap;
struct wm97xx_batt_pdata *batt_pdata;
};
#endif
/*
* Copyright (C) 2016 Robert Jarzmik <robert.jarzmik@free.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef __SOUND_AC97_CODEC2_H
#define __SOUND_AC97_CODEC2_H
#include <linux/device.h>
#define AC97_ID(vendor_id1, vendor_id2) \
((((vendor_id1) & 0xffff) << 16) | ((vendor_id2) & 0xffff))
#define AC97_DRIVER_ID(vendor_id1, vendor_id2, mask_id1, mask_id2, _data) \
{ .id = (((vendor_id1) & 0xffff) << 16) | ((vendor_id2) & 0xffff), \
.mask = (((mask_id1) & 0xffff) << 16) | ((mask_id2) & 0xffff), \
.data = (_data) }
struct ac97_controller;
struct clk;
/**
* struct ac97_id - matches a codec device and driver on an ac97 bus
* @id: The significant bits if the codec vendor ID1 and ID2
* @mask: Bitmask specifying which bits of the id field are significant when
* matching. A driver binds to a device when :
* ((vendorID1 << 8 | vendorID2) & (mask_id1 << 8 | mask_id2)) == id.
* @data: Private data used by the driver.
*/
struct ac97_id {
unsigned int id;
unsigned int mask;
void *data;
};
/**
* ac97_codec_device - a ac97 codec
* @dev: the core device
* @vendor_id: the vendor_id of the codec, as sensed on the AC-link
* @num: the codec number, 0 is primary, 1 is first slave, etc ...
* @clk: the clock BIT_CLK provided by the codec
* @ac97_ctrl: ac97 digital controller on the same AC-link
*
* This is the device instantiated for each codec living on a AC-link. There are
* normally 0 to 4 codec devices per AC-link, and all of them are controlled by
* an AC97 digital controller.
*/
struct ac97_codec_device {
struct device dev;
unsigned int vendor_id;
unsigned int num;
struct clk *clk;
struct ac97_controller *ac97_ctrl;
};
/**
* ac97_codec_driver - a ac97 codec driver
* @driver: the device driver structure
* @probe: the function called when a ac97_codec_device is matched
* @remove: the function called when the device is unbound/removed
* @shutdown: shutdown function (might be NULL)
* @id_table: ac97 vendor_id match table, { } member terminated
*/
struct ac97_codec_driver {
struct device_driver driver;
int (*probe)(struct ac97_codec_device *);
int (*remove)(struct ac97_codec_device *);
void (*shutdown)(struct ac97_codec_device *);
const struct ac97_id *id_table;
};
static inline struct ac97_codec_device *to_ac97_device(struct device *d)
{
return container_of(d, struct ac97_codec_device, dev);
}
static inline struct ac97_codec_driver *to_ac97_driver(struct device_driver *d)
{
return container_of(d, struct ac97_codec_driver, driver);
}
#if IS_ENABLED(CONFIG_AC97_BUS_NEW)
int snd_ac97_codec_driver_register(struct ac97_codec_driver *drv);
void snd_ac97_codec_driver_unregister(struct ac97_codec_driver *drv);
#else
static inline int
snd_ac97_codec_driver_register(struct ac97_codec_driver *drv)
{
return 0;
}
static inline void
snd_ac97_codec_driver_unregister(struct ac97_codec_driver *drv)
{
}
#endif
static inline struct device *
ac97_codec_dev2dev(struct ac97_codec_device *adev)
{
return &adev->dev;
}
static inline void *ac97_get_drvdata(struct ac97_codec_device *adev)
{
return dev_get_drvdata(ac97_codec_dev2dev(adev));
}
static inline void ac97_set_drvdata(struct ac97_codec_device *adev,
void *data)
{
dev_set_drvdata(ac97_codec_dev2dev(adev), data);
}
void *snd_ac97_codec_get_platdata(const struct ac97_codec_device *adev);
#endif
/*
* Copyright (C) 2016 Robert Jarzmik <robert.jarzmik@free.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This file is for backward compatibility with snd_ac97 structure and its
* multiple usages, such as the snd_ac97_bus and snd_ac97_build_ops.
*
*/
#ifndef AC97_COMPAT_H
#define AC97_COMPAT_H
#include <sound/ac97_codec.h>
struct snd_ac97 *snd_ac97_compat_alloc(struct ac97_codec_device *adev);
void snd_ac97_compat_release(struct snd_ac97 *ac97);
#endif
/*
* Copyright (C) 2016 Robert Jarzmik <robert.jarzmik@free.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef AC97_CONTROLLER_H
#define AC97_CONTROLLER_H
#include <linux/device.h>
#include <linux/list.h>
#define AC97_BUS_MAX_CODECS 4
#define AC97_SLOTS_AVAILABLE_ALL 0xf
struct ac97_controller_ops;
/**
* struct ac97_controller - The AC97 controller of the AC-Link
* @ops: the AC97 operations.
* @controllers: linked list of all existing controllers.
* @adap: the shell device ac97-%d, ie. ac97 adapter
* @nr: the number of the shell device
* @slots_available: the mask of accessible/scanable codecs.
* @parent: the device providing the AC97 controller.
* @codecs: the 4 possible AC97 codecs (NULL if none found).
* @codecs_pdata: platform_data for each codec (NULL if no pdata).
*
* This structure is internal to AC97 bus, and should not be used by the
* controllers themselves, excepting for using @dev.
*/
struct ac97_controller {
const struct ac97_controller_ops *ops;
struct list_head controllers;
struct device adap;
int nr;
unsigned short slots_available;
struct device *parent;
struct ac97_codec_device *codecs[AC97_BUS_MAX_CODECS];
void *codecs_pdata[AC97_BUS_MAX_CODECS];
};
/**
* struct ac97_controller_ops - The AC97 operations
* @reset: Cold reset of the AC97 AC-Link.
* @warm_reset: Warm reset of the AC97 AC-Link.
* @read: Read of a single AC97 register.
* Returns the register value or a negative error code.
* @write: Write of a single AC97 register.
*
* These are the basic operation an AC97 controller must provide for an AC97
* access functions. Amongst these, all but the last 2 are mandatory.
* The slot number is also known as the AC97 codec number, between 0 and 3.
*/
struct ac97_controller_ops {
void (*reset)(struct ac97_controller *adrv);
void (*warm_reset)(struct ac97_controller *adrv);
int (*write)(struct ac97_controller *adrv, int slot,
unsigned short reg, unsigned short val);
int (*read)(struct ac97_controller *adrv, int slot, unsigned short reg);
};
#if IS_ENABLED(CONFIG_AC97_BUS_NEW)
struct ac97_controller *snd_ac97_controller_register(
const struct ac97_controller_ops *ops, struct device *dev,
unsigned short slots_available, void **codecs_pdata);
void snd_ac97_controller_unregister(struct ac97_controller *ac97_ctrl);
#else
static inline struct ac97_controller *
snd_ac97_controller_register(const struct ac97_controller_ops *ops,
struct device *dev,
unsigned short slots_available,
void **codecs_pdata)
{
return ERR_PTR(-ENODEV);
}
static inline void
snd_ac97_controller_unregister(struct ac97_controller *ac97_ctrl)
{
}
#endif
#endif
This diff is collapsed.
This diff is collapsed.
......@@ -2,10 +2,13 @@
#ifndef PXA2XX_LIB_H
#define PXA2XX_LIB_H
#include <uapi/sound/asound.h>
#include <linux/platform_device.h>
#include <sound/ac97_codec.h>
/* PCM */
struct snd_pcm_substream;
struct snd_pcm_hw_params;
struct snd_pcm;
extern int __pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params);
......@@ -22,12 +25,12 @@ extern void pxa2xx_pcm_free_dma_buffers(struct snd_pcm *pcm);
/* AC97 */
extern unsigned short pxa2xx_ac97_read(struct snd_ac97 *ac97, unsigned short reg);
extern void pxa2xx_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val);
extern int pxa2xx_ac97_read(int slot, unsigned short reg);
extern int pxa2xx_ac97_write(int slot, unsigned short reg, unsigned short val);
extern bool pxa2xx_ac97_try_warm_reset(struct snd_ac97 *ac97);
extern bool pxa2xx_ac97_try_cold_reset(struct snd_ac97 *ac97);
extern void pxa2xx_ac97_finish_reset(struct snd_ac97 *ac97);
extern bool pxa2xx_ac97_try_warm_reset(void);
extern bool pxa2xx_ac97_try_cold_reset(void);
extern void pxa2xx_ac97_finish_reset(void);
extern int pxa2xx_ac97_hw_suspend(void);
extern int pxa2xx_ac97_hw_resume(void);
......
......@@ -80,6 +80,8 @@ source "sound/hda/Kconfig"
source "sound/ppc/Kconfig"
source "sound/ac97/Kconfig"
source "sound/aoa/Kconfig"
source "sound/arm/Kconfig"
......
......@@ -11,6 +11,7 @@ obj-$(CONFIG_SND_AOA) += aoa/
# This one must be compilable even if sound is configured out
obj-$(CONFIG_AC97_BUS) += ac97_bus.o
obj-$(CONFIG_AC97_BUS_NEW) += ac97/
ifeq ($(CONFIG_SND),y)
obj-y += last.o
......
#
# AC97 configuration
#
config AC97_BUS_NEW
tristate
select AC97
help
This is the new AC97 bus type, successor of AC97_BUS. The ported
drivers which benefit from the AC97 automatic probing should "select"
this instead of the AC97_BUS.
Say Y here if you want to have AC97 devices, which are sound oriented
devices around an AC-Link.
config AC97_BUS_COMPAT
bool
depends on AC97_BUS_NEW
depends on !AC97_BUS
#
# make for AC97 bus drivers
#
obj-$(CONFIG_AC97_BUS_NEW) += ac97.o
ac97-y += bus.o codec.o
ac97-$(CONFIG_AC97_BUS_COMPAT) += snd_ac97_compat.o
/*
* Copyright (C) 2016 Robert Jarzmik <robert.jarzmik@free.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
unsigned int snd_ac97_bus_scan_one(struct ac97_controller *ac97,
unsigned int codec_num);
static inline bool ac97_ids_match(unsigned int id1, unsigned int id2,
unsigned int mask)
{
return (id1 & mask) == (id2 & mask);
}
This diff is collapsed.
/*
* Copyright (C) 2016 Robert Jarzmik <robert.jarzmik@free.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <sound/ac97_codec.h>
#include <sound/ac97/codec.h>
#include <sound/ac97/controller.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <sound/soc.h> /* For compat_ac97_* */
/*
* Copyright (C) 2016 Robert Jarzmik <robert.jarzmik@free.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/list.h>
#include <linux/slab.h>
#include <sound/ac97/codec.h>
#include <sound/ac97/compat.h>
#include <sound/ac97/controller.h>
#include <sound/soc.h>
#include "ac97_core.h"
static void compat_ac97_reset(struct snd_ac97 *ac97)
{
struct ac97_codec_device *adev = to_ac97_device(ac97->private_data);
struct ac97_controller *actrl = adev->ac97_ctrl;
if (actrl->ops->reset)
actrl->ops->reset(actrl);
}
static void compat_ac97_warm_reset(struct snd_ac97 *ac97)
{
struct ac97_codec_device *adev = to_ac97_device(ac97->private_data);
struct ac97_controller *actrl = adev->ac97_ctrl;
if (actrl->ops->warm_reset)
actrl->ops->warm_reset(actrl);
}
static void compat_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
unsigned short val)
{
struct ac97_codec_device *adev = to_ac97_device(ac97->private_data);
struct ac97_controller *actrl = adev->ac97_ctrl;
actrl->ops->write(actrl, ac97->num, reg, val);
}
static unsigned short compat_ac97_read(struct snd_ac97 *ac97,
unsigned short reg)
{
struct ac97_codec_device *adev = to_ac97_device(ac97->private_data);
struct ac97_controller *actrl = adev->ac97_ctrl;
return actrl->ops->read(actrl, ac97->num, reg);
}
static struct snd_ac97_bus_ops compat_snd_ac97_bus_ops = {
.reset = compat_ac97_reset,
.warm_reset = compat_ac97_warm_reset,
.write = compat_ac97_write,
.read = compat_ac97_read,
};
static struct snd_ac97_bus compat_soc_ac97_bus = {
.ops = &compat_snd_ac97_bus_ops,
};
struct snd_ac97 *snd_ac97_compat_alloc(struct ac97_codec_device *adev)
{
struct snd_ac97 *ac97;
ac97 = kzalloc(sizeof(struct snd_ac97), GFP_KERNEL);
if (ac97 == NULL)
return ERR_PTR(-ENOMEM);
ac97->dev = adev->dev;
ac97->private_data = adev;
ac97->bus = &compat_soc_ac97_bus;
return ac97;
}
EXPORT_SYMBOL_GPL(snd_ac97_compat_alloc);
void snd_ac97_compat_release(struct snd_ac97 *ac97)
{
kfree(ac97);
}
EXPORT_SYMBOL_GPL(snd_ac97_compat_release);
int snd_ac97_reset(struct snd_ac97 *ac97, bool try_warm, unsigned int id,
unsigned int id_mask)
{
struct ac97_codec_device *adev = to_ac97_device(ac97->private_data);
struct ac97_controller *actrl = adev->ac97_ctrl;
unsigned int scanned;
if (try_warm) {
compat_ac97_warm_reset(ac97);
scanned = snd_ac97_bus_scan_one(actrl, adev->num);
if (ac97_ids_match(scanned, adev->vendor_id, id_mask))
return 1;
}
compat_ac97_reset(ac97);
compat_ac97_warm_reset(ac97);
scanned = snd_ac97_bus_scan_one(actrl, adev->num);
if (ac97_ids_match(scanned, adev->vendor_id, id_mask))
return 0;
return -ENODEV;
}
EXPORT_SYMBOL_GPL(snd_ac97_reset);
......@@ -20,7 +20,6 @@
#include <linux/io.h>
#include <linux/gpio.h>
#include <sound/ac97_codec.h>
#include <sound/pxa2xx-lib.h>
#include <mach/irqs.h>
......@@ -46,38 +45,41 @@ extern void pxa27x_configure_ac97reset(int reset_gpio, bool to_gpio);
* 1 jiffy timeout if interrupt never comes).
*/
unsigned short pxa2xx_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
int pxa2xx_ac97_read(int slot, unsigned short reg)
{
unsigned short val = -1;
int val = -ENODEV;
volatile u32 *reg_addr;
if (slot > 0)
return -ENODEV;
mutex_lock(&car_mutex);
/* set up primary or secondary codec space */
if (cpu_is_pxa25x() && reg == AC97_GPIO_STATUS)
reg_addr = ac97->num ? &SMC_REG_BASE : &PMC_REG_BASE;
reg_addr = slot ? &SMC_REG_BASE : &PMC_REG_BASE;
else
reg_addr = ac97->num ? &SAC_REG_BASE : &PAC_REG_BASE;
reg_addr = slot ? &SAC_REG_BASE : &PAC_REG_BASE;
reg_addr += (reg >> 1);
/* start read access across the ac97 link */
GSR = GSR_CDONE | GSR_SDONE;
gsr_bits = 0;
val = *reg_addr;
val = (*reg_addr & 0xffff);
if (reg == AC97_GPIO_STATUS)
goto out;
if (wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_SDONE, 1) <= 0 &&
!((GSR | gsr_bits) & GSR_SDONE)) {
printk(KERN_ERR "%s: read error (ac97_reg=%d GSR=%#lx)\n",
__func__, reg, GSR | gsr_bits);
val = -1;
val = -ETIMEDOUT;
goto out;
}
/* valid data now */
GSR = GSR_CDONE | GSR_SDONE;
gsr_bits = 0;
val = *reg_addr;
val = (*reg_addr & 0xffff);
/* but we've just started another cycle... */
wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_SDONE, 1);
......@@ -86,29 +88,32 @@ out: mutex_unlock(&car_mutex);
}
EXPORT_SYMBOL_GPL(pxa2xx_ac97_read);
void pxa2xx_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
unsigned short val)
int pxa2xx_ac97_write(int slot, unsigned short reg, unsigned short val)
{
volatile u32 *reg_addr;
int ret = 0;
mutex_lock(&car_mutex);
/* set up primary or secondary codec space */
if (cpu_is_pxa25x() && reg == AC97_GPIO_STATUS)
reg_addr = ac97->num ? &SMC_REG_BASE : &PMC_REG_BASE;
reg_addr = slot ? &SMC_REG_BASE : &PMC_REG_BASE;
else
reg_addr = ac97->num ? &SAC_REG_BASE : &PAC_REG_BASE;
reg_addr = slot ? &SAC_REG_BASE : &PAC_REG_BASE;
reg_addr += (reg >> 1);
GSR = GSR_CDONE | GSR_SDONE;
gsr_bits = 0;
*reg_addr = val;
if (wait_event_timeout(gsr_wq, (GSR | gsr_bits) & GSR_CDONE, 1) <= 0 &&
!((GSR | gsr_bits) & GSR_CDONE))
!((GSR | gsr_bits) & GSR_CDONE)) {
printk(KERN_ERR "%s: write error (ac97_reg=%d GSR=%#lx)\n",
__func__, reg, GSR | gsr_bits);
ret = -EIO;
}
mutex_unlock(&car_mutex);
return ret;
}
EXPORT_SYMBOL_GPL(pxa2xx_ac97_write);
......@@ -188,7 +193,7 @@ static inline void pxa_ac97_cold_pxa3xx(void)
}
#endif
bool pxa2xx_ac97_try_warm_reset(struct snd_ac97 *ac97)
bool pxa2xx_ac97_try_warm_reset(void)
{
unsigned long gsr;
unsigned int timeout = 100;
......@@ -225,7 +230,7 @@ bool pxa2xx_ac97_try_warm_reset(struct snd_ac97 *ac97)
}
EXPORT_SYMBOL_GPL(pxa2xx_ac97_try_warm_reset);
bool pxa2xx_ac97_try_cold_reset(struct snd_ac97 *ac97)
bool pxa2xx_ac97_try_cold_reset(void)
{
unsigned long gsr;
unsigned int timeout = 1000;
......@@ -263,7 +268,7 @@ bool pxa2xx_ac97_try_cold_reset(struct snd_ac97 *ac97)
EXPORT_SYMBOL_GPL(pxa2xx_ac97_try_cold_reset);
void pxa2xx_ac97_finish_reset(struct snd_ac97 *ac97)
void pxa2xx_ac97_finish_reset(void)
{
GCR &= ~(GCR_PRIRDY_IEN|GCR_SECRDY_IEN);
GCR |= GCR_SDONE_IE|GCR_CDONE_IE;
......
......@@ -29,19 +29,38 @@
#include "pxa2xx-pcm.h"
static void pxa2xx_ac97_reset(struct snd_ac97 *ac97)
static void pxa2xx_ac97_legacy_reset(struct snd_ac97 *ac97)
{
if (!pxa2xx_ac97_try_cold_reset(ac97)) {
pxa2xx_ac97_try_warm_reset(ac97);
}
if (!pxa2xx_ac97_try_cold_reset())
pxa2xx_ac97_try_warm_reset();
pxa2xx_ac97_finish_reset();
}
static unsigned short pxa2xx_ac97_legacy_read(struct snd_ac97 *ac97,
unsigned short reg)
{
int ret;
ret = pxa2xx_ac97_read(ac97->num, reg);
if (ret < 0)
return 0;
else
return (unsigned short)(ret & 0xffff);
}
static void pxa2xx_ac97_legacy_write(struct snd_ac97 *ac97,
unsigned short reg, unsigned short val)
{
int __always_unused ret;
pxa2xx_ac97_finish_reset(ac97);
ret = pxa2xx_ac97_write(ac97->num, reg, val);
}
static struct snd_ac97_bus_ops pxa2xx_ac97_ops = {
.read = pxa2xx_ac97_read,
.write = pxa2xx_ac97_write,
.reset = pxa2xx_ac97_reset,
.read = pxa2xx_ac97_legacy_read,
.write = pxa2xx_ac97_legacy_write,
.reset = pxa2xx_ac97_legacy_reset,
};
static struct pxad_param pxa2xx_ac97_pcm_out_req = {
......
......@@ -2,3 +2,10 @@ config SND_SOC_AMD_ACP
tristate "AMD Audio Coprocessor support"
help
This option enables ACP DMA support on AMD platform.
config SND_SOC_AMD_CZ_RT5645_MACH
tristate "AMD CZ support for RT5645"
select SND_SOC_RT5645
depends on SND_SOC_AMD_ACP && I2C
help
This option enables machine driver for rt5645.
snd-soc-acp-pcm-objs := acp-pcm-dma.o
acp_audio_dma-objs := acp-pcm-dma.o
snd-soc-acp-rt5645-mach-objs := acp-rt5645.o
obj-$(CONFIG_SND_SOC_AMD_ACP) += snd-soc-acp-pcm.o
obj-$(CONFIG_SND_SOC_AMD_ACP) += acp_audio_dma.o
obj-$(CONFIG_SND_SOC_AMD_CZ_RT5645_MACH) += snd-soc-acp-rt5645-mach.o
This diff is collapsed.
/*
* Machine driver for AMD ACP Audio engine using Realtek RT5645 codec
*
* Copyright 2017 Advanced Micro Devices, Inc.
*
* This file is modified from rt288 machine driver
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
*
*/
#include <sound/core.h>
#include <sound/soc.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc-dapm.h>
#include <sound/jack.h>
#include <linux/gpio.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/acpi.h>
#include "../codecs/rt5645.h"
#define CZ_PLAT_CLK 24000000
static struct snd_soc_jack cz_jack;
static int cz_aif1_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
int ret = 0;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
ret = snd_soc_dai_set_pll(codec_dai, 0, RT5645_PLL1_S_MCLK,
CZ_PLAT_CLK, params_rate(params) * 512);
if (ret < 0) {
dev_err(rtd->dev, "can't set codec pll: %d\n", ret);
return ret;
}
ret = snd_soc_dai_set_sysclk(codec_dai, RT5645_SCLK_S_PLL1,
params_rate(params) * 512, SND_SOC_CLOCK_OUT);
if (ret < 0) {
dev_err(rtd->dev, "can't set codec sysclk: %d\n", ret);
return ret;
}
return ret;
}
static int cz_init(struct snd_soc_pcm_runtime *rtd)
{
int ret;
struct snd_soc_card *card;
struct snd_soc_codec *codec;
codec = rtd->codec;
card = rtd->card;
ret = snd_soc_card_jack_new(card, "Headset Jack",
SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
SND_JACK_BTN_0 | SND_JACK_BTN_1 |
SND_JACK_BTN_2 | SND_JACK_BTN_3,
&cz_jack, NULL, 0);
if (ret) {
dev_err(card->dev, "HP jack creation failed %d\n", ret);
return ret;
}
rt5645_set_jack_detect(codec, &cz_jack, &cz_jack, &cz_jack);
return 0;
}
static struct snd_soc_ops cz_aif1_ops = {
.hw_params = cz_aif1_hw_params,
};
static struct snd_soc_dai_link cz_dai_rt5650[] = {
{
.name = "amd-rt5645-play",
.stream_name = "RT5645_AIF1",
.platform_name = "acp_audio_dma.0.auto",
.cpu_dai_name = "designware-i2s.1.auto",
.codec_dai_name = "rt5645-aif1",
.codec_name = "i2c-10EC5650:00",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
| SND_SOC_DAIFMT_CBM_CFM,
.init = cz_init,
.ops = &cz_aif1_ops,
},
{
.name = "amd-rt5645-cap",
.stream_name = "RT5645_AIF1",
.platform_name = "acp_audio_dma.0.auto",
.cpu_dai_name = "designware-i2s.2.auto",
.codec_dai_name = "rt5645-aif1",
.codec_name = "i2c-10EC5650:00",
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
| SND_SOC_DAIFMT_CBM_CFM,
.ops = &cz_aif1_ops,
},
};
static const struct snd_soc_dapm_widget cz_widgets[] = {
SND_SOC_DAPM_HP("Headphones", NULL),
SND_SOC_DAPM_SPK("Speakers", NULL),
SND_SOC_DAPM_MIC("Headset Mic", NULL),
SND_SOC_DAPM_MIC("Int Mic", NULL),
};
static const struct snd_soc_dapm_route cz_audio_route[] = {
{"Headphones", NULL, "HPOL"},
{"Headphones", NULL, "HPOR"},
{"RECMIXL", NULL, "Headset Mic"},
{"RECMIXR", NULL, "Headset Mic"},
{"Speakers", NULL, "SPOL"},
{"Speakers", NULL, "SPOR"},
{"DMIC L2", NULL, "Int Mic"},
{"DMIC R2", NULL, "Int Mic"},
};
static const struct snd_kcontrol_new cz_mc_controls[] = {
SOC_DAPM_PIN_SWITCH("Headphones"),
SOC_DAPM_PIN_SWITCH("Speakers"),
SOC_DAPM_PIN_SWITCH("Headset Mic"),
SOC_DAPM_PIN_SWITCH("Int Mic"),
};
static struct snd_soc_card cz_card = {
.name = "acprt5650",
.owner = THIS_MODULE,
.dai_link = cz_dai_rt5650,
.num_links = ARRAY_SIZE(cz_dai_rt5650),
.dapm_widgets = cz_widgets,
.num_dapm_widgets = ARRAY_SIZE(cz_widgets),
.dapm_routes = cz_audio_route,
.num_dapm_routes = ARRAY_SIZE(cz_audio_route),
.controls = cz_mc_controls,
.num_controls = ARRAY_SIZE(cz_mc_controls),
};
static int cz_probe(struct platform_device *pdev)
{
int ret;
struct snd_soc_card *card;
card = &cz_card;
cz_card.dev = &pdev->dev;
platform_set_drvdata(pdev, card);
ret = devm_snd_soc_register_card(&pdev->dev, &cz_card);
if (ret) {
dev_err(&pdev->dev,
"devm_snd_soc_register_card(%s) failed: %d\n",
cz_card.name, ret);
return ret;
}
return 0;
}
static const struct acpi_device_id cz_audio_acpi_match[] = {
{ "AMDI1002", 0 },
{},
};
MODULE_DEVICE_TABLE(acpi, cz_audio_acpi_match);
static struct platform_driver cz_pcm_driver = {
.driver = {
.name = "cz-rt5645",
.acpi_match_table = ACPI_PTR(cz_audio_acpi_match),
.pm = &snd_soc_pm_ops,
},
.probe = cz_probe,
};
module_platform_driver(cz_pcm_driver);
MODULE_AUTHOR("akshu.agrawal@amd.com");
MODULE_DESCRIPTION("cz-rt5645 audio support");
MODULE_LICENSE("GPL v2");
......@@ -20,6 +20,7 @@
/* Capture SRAM address (as a source in dma descriptor) */
#define ACP_SHARED_RAM_BANK_5_ADDRESS 0x400A000
#define ACP_SHARED_RAM_BANK_3_ADDRESS 0x4006000
#define ACP_DMA_RESET_TIME 10000
#define ACP_CLOCK_EN_TIME_OUT_VALUE 0x000000FF
......@@ -68,6 +69,7 @@
#define CAPTURE_START_DMA_DESCR_CH15 6
#define CAPTURE_END_DMA_DESCR_CH15 7
#define mmACP_I2S_16BIT_RESOLUTION_EN 0x5209
enum acp_dma_priority_level {
/* 0x0 Specifies the DMA channel is given normal priority */
ACP_DMA_PRIORITY_LEVEL_NORMAL = 0x0,
......@@ -82,9 +84,26 @@ struct audio_substream_data {
u16 num_of_pages;
u16 direction;
uint64_t size;
u64 renderbytescount;
u64 capturebytescount;
void __iomem *acp_mmio;
};
struct audio_drv_data {
struct snd_pcm_substream *play_stream;
struct snd_pcm_substream *capture_stream;
void __iomem *acp_mmio;
u32 asic_type;
};
union acp_dma_count {
struct {
u32 low;
u32 high;
} bcount;
u64 bytescount;
};
enum {
ACP_TILE_P1 = 0,
ACP_TILE_P2,
......
......@@ -13,6 +13,7 @@
#include <linux/delay.h>
#include <linux/gcd.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/pm_runtime.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
......@@ -293,16 +294,99 @@ int arizona_init_gpio(struct snd_soc_codec *codec)
}
EXPORT_SYMBOL_GPL(arizona_init_gpio);
int arizona_init_notifiers(struct snd_soc_codec *codec)
int arizona_init_common(struct arizona *arizona)
{
struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
struct arizona *arizona = priv->arizona;
struct arizona_pdata *pdata = &arizona->pdata;
unsigned int val, mask;
int i;
BLOCKING_INIT_NOTIFIER_HEAD(&arizona->notifier);
for (i = 0; i < ARIZONA_MAX_OUTPUT; ++i) {
/* Default is 0 so noop with defaults */
if (pdata->out_mono[i])
val = ARIZONA_OUT1_MONO;
else
val = 0;
regmap_update_bits(arizona->regmap,
ARIZONA_OUTPUT_PATH_CONFIG_1L + (i * 8),
ARIZONA_OUT1_MONO, val);
}
for (i = 0; i < ARIZONA_MAX_PDM_SPK; i++) {
if (pdata->spk_mute[i])
regmap_update_bits(arizona->regmap,
ARIZONA_PDM_SPK1_CTRL_1 + (i * 2),
ARIZONA_SPK1_MUTE_ENDIAN_MASK |
ARIZONA_SPK1_MUTE_SEQ1_MASK,
pdata->spk_mute[i]);
if (pdata->spk_fmt[i])
regmap_update_bits(arizona->regmap,
ARIZONA_PDM_SPK1_CTRL_2 + (i * 2),
ARIZONA_SPK1_FMT_MASK,
pdata->spk_fmt[i]);
}
for (i = 0; i < ARIZONA_MAX_INPUT; i++) {
/* Default for both is 0 so noop with defaults */
val = pdata->dmic_ref[i] << ARIZONA_IN1_DMIC_SUP_SHIFT;
if (pdata->inmode[i] & ARIZONA_INMODE_DMIC)
val |= 1 << ARIZONA_IN1_MODE_SHIFT;
switch (arizona->type) {
case WM8998:
case WM1814:
regmap_update_bits(arizona->regmap,
ARIZONA_ADC_DIGITAL_VOLUME_1L + (i * 8),
ARIZONA_IN1L_SRC_SE_MASK,
(pdata->inmode[i] & ARIZONA_INMODE_SE)
<< ARIZONA_IN1L_SRC_SE_SHIFT);
regmap_update_bits(arizona->regmap,
ARIZONA_ADC_DIGITAL_VOLUME_1R + (i * 8),
ARIZONA_IN1R_SRC_SE_MASK,
(pdata->inmode[i] & ARIZONA_INMODE_SE)
<< ARIZONA_IN1R_SRC_SE_SHIFT);
mask = ARIZONA_IN1_DMIC_SUP_MASK |
ARIZONA_IN1_MODE_MASK;
break;
default:
if (pdata->inmode[i] & ARIZONA_INMODE_SE)
val |= 1 << ARIZONA_IN1_SINGLE_ENDED_SHIFT;
mask = ARIZONA_IN1_DMIC_SUP_MASK |
ARIZONA_IN1_MODE_MASK |
ARIZONA_IN1_SINGLE_ENDED_MASK;
break;
}
regmap_update_bits(arizona->regmap,
ARIZONA_IN1L_CONTROL + (i * 8),
mask, val);
}
return 0;
}
EXPORT_SYMBOL_GPL(arizona_init_notifiers);
EXPORT_SYMBOL_GPL(arizona_init_common);
int arizona_init_vol_limit(struct arizona *arizona)
{
int i;
for (i = 0; i < ARRAY_SIZE(arizona->pdata.out_vol_limit); ++i) {
if (arizona->pdata.out_vol_limit[i])
regmap_update_bits(arizona->regmap,
ARIZONA_DAC_VOLUME_LIMIT_1L + i * 4,
ARIZONA_OUT1L_VOL_LIM_MASK,
arizona->pdata.out_vol_limit[i]);
}
return 0;
}
EXPORT_SYMBOL_GPL(arizona_init_vol_limit);
const char * const arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = {
"None",
......@@ -2695,6 +2779,80 @@ int arizona_lhpf_coeff_put(struct snd_kcontrol *kcontrol,
}
EXPORT_SYMBOL_GPL(arizona_lhpf_coeff_put);
int arizona_of_get_audio_pdata(struct arizona *arizona)
{
struct arizona_pdata *pdata = &arizona->pdata;
struct device_node *np = arizona->dev->of_node;
struct property *prop;
const __be32 *cur;
u32 val;
u32 pdm_val[ARIZONA_MAX_PDM_SPK];
int ret;
int count = 0;
count = 0;
of_property_for_each_u32(np, "wlf,inmode", prop, cur, val) {
if (count == ARRAY_SIZE(pdata->inmode))
break;
pdata->inmode[count] = val;
count++;
}
count = 0;
of_property_for_each_u32(np, "wlf,dmic-ref", prop, cur, val) {
if (count == ARRAY_SIZE(pdata->dmic_ref))
break;
pdata->dmic_ref[count] = val;
count++;
}
count = 0;
of_property_for_each_u32(np, "wlf,out-mono", prop, cur, val) {
if (count == ARRAY_SIZE(pdata->out_mono))
break;
pdata->out_mono[count] = !!val;
count++;
}
count = 0;
of_property_for_each_u32(np, "wlf,max-channels-clocked", prop, cur, val) {
if (count == ARRAY_SIZE(pdata->max_channels_clocked))
break;
pdata->max_channels_clocked[count] = val;
count++;
}
count = 0;
of_property_for_each_u32(np, "wlf,out-volume-limit", prop, cur, val) {
if (count == ARRAY_SIZE(pdata->out_vol_limit))
break;
pdata->out_vol_limit[count] = val;
count++;
}
ret = of_property_read_u32_array(np, "wlf,spk-fmt",
pdm_val, ARRAY_SIZE(pdm_val));
if (ret >= 0)
for (count = 0; count < ARRAY_SIZE(pdata->spk_fmt); ++count)
pdata->spk_fmt[count] = pdm_val[count];
ret = of_property_read_u32_array(np, "wlf,spk-mute",
pdm_val, ARRAY_SIZE(pdm_val));
if (ret >= 0)
for (count = 0; count < ARRAY_SIZE(pdata->spk_mute); ++count)
pdata->spk_mute[count] = pdm_val[count];
return 0;
}
EXPORT_SYMBOL_GPL(arizona_of_get_audio_pdata);
MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support");
MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
MODULE_LICENSE("GPL");
......@@ -313,7 +313,9 @@ int arizona_set_fll(struct arizona_fll *fll, int source,
int arizona_init_spk(struct snd_soc_codec *codec);
int arizona_init_gpio(struct snd_soc_codec *codec);
int arizona_init_mono(struct snd_soc_codec *codec);
int arizona_init_notifiers(struct snd_soc_codec *codec);
int arizona_init_common(struct arizona *arizona);
int arizona_init_vol_limit(struct arizona *arizona);
int arizona_init_spk_irqs(struct arizona *arizona);
int arizona_free_spk_irqs(struct arizona *arizona);
......@@ -350,4 +352,6 @@ static inline int arizona_unregister_notifier(struct snd_soc_codec *codec,
return blocking_notifier_chain_unregister(&arizona->notifier, nb);
}
int arizona_of_get_audio_pdata(struct arizona *arizona);
#endif
......@@ -1130,7 +1130,6 @@ static int cs47l24_codec_probe(struct snd_soc_codec *codec)
arizona_init_gpio(codec);
arizona_init_mono(codec);
arizona_init_notifiers(codec);
ret = wm_adsp2_codec_probe(&priv->core.adsp[1], codec);
if (ret)
......@@ -1230,6 +1229,14 @@ static int cs47l24_probe(struct platform_device *pdev)
if (!cs47l24)
return -ENOMEM;
if (IS_ENABLED(CONFIG_OF)) {
if (!dev_get_platdata(arizona->dev)) {
ret = arizona_of_get_audio_pdata(arizona);
if (ret < 0)
return ret;
}
}
platform_set_drvdata(pdev, cs47l24);
cs47l24->core.arizona = arizona;
......@@ -1288,6 +1295,11 @@ static int cs47l24_probe(struct platform_device *pdev)
return ret;
}
arizona_init_common(arizona);
ret = arizona_init_vol_limit(arizona);
if (ret < 0)
goto err_dsp_irq;
ret = arizona_init_spk_irqs(arizona);
if (ret < 0)
goto err_dsp_irq;
......
......@@ -1951,7 +1951,6 @@ static int wm5102_codec_probe(struct snd_soc_codec *codec)
return ret;
arizona_init_gpio(codec);
arizona_init_notifiers(codec);
snd_soc_component_disable_pin(component, "HAPTICS");
......@@ -2043,6 +2042,14 @@ static int wm5102_probe(struct platform_device *pdev)
return -ENOMEM;
platform_set_drvdata(pdev, wm5102);
if (IS_ENABLED(CONFIG_OF)) {
if (!dev_get_platdata(arizona->dev)) {
ret = arizona_of_get_audio_pdata(arizona);
if (ret < 0)
return ret;
}
}
mutex_init(&arizona->dac_comp_lock);
wm5102->core.arizona = arizona;
......@@ -2098,6 +2105,11 @@ static int wm5102_probe(struct platform_device *pdev)
return ret;
}
arizona_init_common(arizona);
ret = arizona_init_vol_limit(arizona);
if (ret < 0)
goto err_dsp_irq;
ret = arizona_init_spk_irqs(arizona);
if (ret < 0)
goto err_dsp_irq;
......
......@@ -2290,7 +2290,6 @@ static int wm5110_codec_probe(struct snd_soc_codec *codec)
arizona_init_gpio(codec);
arizona_init_mono(codec);
arizona_init_notifiers(codec);
for (i = 0; i < WM5110_NUM_ADSP; ++i) {
ret = wm_adsp2_codec_probe(&priv->core.adsp[i], codec);
......@@ -2398,6 +2397,14 @@ static int wm5110_probe(struct platform_device *pdev)
return -ENOMEM;
platform_set_drvdata(pdev, wm5110);
if (IS_ENABLED(CONFIG_OF)) {
if (!dev_get_platdata(arizona->dev)) {
ret = arizona_of_get_audio_pdata(arizona);
if (ret < 0)
return ret;
}
}
wm5110->core.arizona = arizona;
wm5110->core.num_inputs = 8;
......@@ -2454,6 +2461,11 @@ static int wm5110_probe(struct platform_device *pdev)
return ret;
}
arizona_init_common(arizona);
ret = arizona_init_vol_limit(arizona);
if (ret < 0)
goto err_dsp_irq;
ret = arizona_init_spk_irqs(arizona);
if (ret < 0)
goto err_dsp_irq;
......
......@@ -1068,8 +1068,6 @@ static int wm8997_codec_probe(struct snd_soc_codec *codec)
if (ret < 0)
return ret;
arizona_init_notifiers(codec);
snd_soc_component_disable_pin(component, "HAPTICS");
priv->core.arizona->dapm = dapm;
......@@ -1136,6 +1134,14 @@ static int wm8997_probe(struct platform_device *pdev)
return -ENOMEM;
platform_set_drvdata(pdev, wm8997);
if (IS_ENABLED(CONFIG_OF)) {
if (!dev_get_platdata(arizona->dev)) {
ret = arizona_of_get_audio_pdata(arizona);
if (ret < 0)
return ret;
}
}
wm8997->core.arizona = arizona;
wm8997->core.num_inputs = 4;
......@@ -1168,6 +1174,11 @@ static int wm8997_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
pm_runtime_idle(&pdev->dev);
arizona_init_common(arizona);
ret = arizona_init_vol_limit(arizona);
if (ret < 0)
return ret;
ret = arizona_init_spk_irqs(arizona);
if (ret < 0)
return ret;
......
......@@ -1284,7 +1284,6 @@ static int wm8998_codec_probe(struct snd_soc_codec *codec)
return ret;
arizona_init_gpio(codec);
arizona_init_notifiers(codec);
snd_soc_component_disable_pin(component, "HAPTICS");
......@@ -1353,6 +1352,14 @@ static int wm8998_probe(struct platform_device *pdev)
return -ENOMEM;
platform_set_drvdata(pdev, wm8998);
if (IS_ENABLED(CONFIG_OF)) {
if (!dev_get_platdata(arizona->dev)) {
ret = arizona_of_get_audio_pdata(arizona);
if (ret < 0)
return ret;
}
}
wm8998->core.arizona = arizona;
wm8998->core.num_inputs = 3; /* IN1L, IN1R, IN2 */
......@@ -1377,6 +1384,8 @@ static int wm8998_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
pm_runtime_idle(&pdev->dev);
arizona_init_common(arizona);
ret = arizona_init_spk_irqs(arizona);
if (ret < 0)
return ret;
......
......@@ -29,21 +29,41 @@
static void pxa2xx_ac97_warm_reset(struct snd_ac97 *ac97)
{
pxa2xx_ac97_try_warm_reset(ac97);
pxa2xx_ac97_try_warm_reset();
pxa2xx_ac97_finish_reset(ac97);
pxa2xx_ac97_finish_reset();
}
static void pxa2xx_ac97_cold_reset(struct snd_ac97 *ac97)
{
pxa2xx_ac97_try_cold_reset(ac97);
pxa2xx_ac97_try_cold_reset();
pxa2xx_ac97_finish_reset(ac97);
pxa2xx_ac97_finish_reset();
}
static unsigned short pxa2xx_ac97_legacy_read(struct snd_ac97 *ac97,
unsigned short reg)
{
int ret;
ret = pxa2xx_ac97_read(ac97->num, reg);
if (ret < 0)
return 0;
else
return (unsigned short)(ret & 0xffff);
}
static void pxa2xx_ac97_legacy_write(struct snd_ac97 *ac97,
unsigned short reg, unsigned short val)
{
int ret;
ret = pxa2xx_ac97_write(ac97->num, reg, val);
}
static struct snd_ac97_bus_ops pxa2xx_ac97_ops = {
.read = pxa2xx_ac97_read,
.write = pxa2xx_ac97_write,
.read = pxa2xx_ac97_legacy_read,
.write = pxa2xx_ac97_legacy_write,
.warm_reset = pxa2xx_ac97_warm_reset,
.reset = pxa2xx_ac97_cold_reset,
};
......
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