diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-11-14 18:01:46 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-11-14 18:01:46 -0800 |
commit | 4e4510fec4af08ead21f6934c1410af1f19a8cad (patch) | |
tree | 2bafab4f7cc2cdf2983186b24140f6303d4dfc8c /drivers | |
parent | 4008e6a9bcee2f3b61bb11951de0fb0ed764cb91 (diff) | |
parent | 7087cb8fad5e19113d82f47f351fc6b338948d5f (diff) | |
download | linux-4e4510fec4af08ead21f6934c1410af1f19a8cad.tar.bz2 |
Merge tag 'sound-4.15-rc1' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
Pull sound updates from Takashi Iwai:
"There are no big surprising changes in this cycle, yet not too boring,
either. The biggest change from diffstat POV is the removal of the
legacy OSS driver codes that have been already disabled for a long
time. This will bring a few trivial merge conflicts.
As new features in ASoC side, there are two things: a new AC97 bus
implementation and AMD Stony platform support. Both include the
relevant changes shared with other subsystems, e.g. AC97 MFD changes
and DRM AMD changes.
Some other highlighted topics are:
- A bunch of USB-audio drivers got the hardening against the
malicious device accesses with a new helper code for endpoint
sanity check
- Lots of cleanups for ASoC Intel platform code, including support
for their open source audio firmware
- Continued ASoC core componentization works
- Support for scaling MCLK with sample rate in ASoC simple-card
- Stabler PCM hot-unplug capability, especially for ASoC usages"
* tag 'sound-4.15-rc1' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (302 commits)
Documentation: sound: hd-audio: notes.rst
ASoC: bcm2835: Support left/right justified and DSP modes
ASoC: bcm2835: Enforce full symmetry
ASoC: bcm2835: Support additional samplerates up to 384kHz
ASoC: bcm2835: Add support for TDM modes
ASoC: add mclk-fs support to audio graph card
ASoC: add mclk-fs to audio graph card binding
ASoC: rt5514: work around link error
ASoC: rt5514: mark PM functions as __maybe_unused
ASoC: rt5663: Check the JD status in the button pushing
ASoC: amd: Modified DMA transfer Mechanism for Playback
ASoC: rt5645: Wait for 400msec before concluding on value of RT5645_VENDOR_ID2
ASoC: sun4i-codec: fixed 32bit audio capture support for H3/H2+
ASoC: da7213: add support for DSP modes
ASoC: sun8i-codec: Add a comment on the LRCK inversion
ASoC: sun8i-codec: Set the BCLK divider
ASoC: rt5663: Delay and retry reading rt5663 ID register
ASoC: amd: use do_div rather than 64 bit division to fix 32 bit builds
ASoC: cs42l56: Fix reset GPIO name in example DT binding
ASoC: rt5514-spi: check irq status to schedule data copy in resume function
...
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/include/amd_shared.h | 29 | ||||
-rw-r--r-- | drivers/input/touchscreen/Kconfig | 2 | ||||
-rw-r--r-- | drivers/input/touchscreen/wm97xx-core.c | 252 | ||||
-rw-r--r-- | drivers/mfd/Kconfig | 14 | ||||
-rw-r--r-- | drivers/mfd/Makefile | 1 | ||||
-rw-r--r-- | drivers/mfd/arizona-core.c | 132 | ||||
-rw-r--r-- | drivers/mfd/wm97xx-core.c | 366 | ||||
-rw-r--r-- | drivers/usb/core/urb.c | 30 |
9 files changed, 583 insertions, 245 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c index a52795d9b458..ebca22302ebb 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.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; diff --git a/drivers/gpu/drm/amd/include/amd_shared.h b/drivers/gpu/drm/amd/include/amd_shared.h index 70e8c20acb2f..3a49fbd8baf8 100644 --- a/drivers/gpu/drm/amd/include/amd_shared.h +++ b/drivers/gpu/drm/amd/include/amd_shared.h @@ -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 diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 64b30fe273fd..176b1a74b2b7 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -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 diff --git a/drivers/input/touchscreen/wm97xx-core.c b/drivers/input/touchscreen/wm97xx-core.c index c9d1c91e1887..fd714ee881f7 100644 --- a/drivers/input/touchscreen/wm97xx-core.c +++ b/drivers/input/touchscreen/wm97xx-core.c @@ -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); diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index fc5e4fef89d2..ac5ad6d0837c 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -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) diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 8703ff17998e..0235e6766bc1 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -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 diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c index 8d46e3ad9529..77875250abe5 100644 --- a/drivers/mfd/arizona-core.c +++ b/drivers/mfd/arizona-core.c @@ -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); diff --git a/drivers/mfd/wm97xx-core.c b/drivers/mfd/wm97xx-core.c new file mode 100644 index 000000000000..4141ee52a70b --- /dev/null +++ b/drivers/mfd/wm97xx-core.c @@ -0,0 +1,366 @@ +/* + * 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"); + diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index f501af0b3079..9fdf137c4865 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -187,6 +187,31 @@ EXPORT_SYMBOL_GPL(usb_unanchor_urb); /*-------------------------------------------------------------------*/ +static const int pipetypes[4] = { + PIPE_CONTROL, PIPE_ISOCHRONOUS, PIPE_BULK, PIPE_INTERRUPT +}; + +/** + * usb_urb_ep_type_check - sanity check of endpoint in the given urb + * @urb: urb to be checked + * + * This performs a light-weight sanity check for the endpoint in the + * given urb. It returns 0 if the urb contains a valid endpoint, otherwise + * a negative error code. + */ +int usb_urb_ep_type_check(const struct urb *urb) +{ + const struct usb_host_endpoint *ep; + + ep = usb_pipe_endpoint(urb->dev, urb->pipe); + if (!ep) + return -EINVAL; + if (usb_pipetype(urb->pipe) != pipetypes[usb_endpoint_type(&ep->desc)]) + return -EINVAL; + return 0; +} +EXPORT_SYMBOL_GPL(usb_urb_ep_type_check); + /** * usb_submit_urb - issue an asynchronous transfer request for an endpoint * @urb: pointer to the urb describing the request @@ -326,9 +351,6 @@ EXPORT_SYMBOL_GPL(usb_unanchor_urb); */ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) { - static int pipetypes[4] = { - PIPE_CONTROL, PIPE_ISOCHRONOUS, PIPE_BULK, PIPE_INTERRUPT - }; int xfertype, max; struct usb_device *dev; struct usb_host_endpoint *ep; @@ -444,7 +466,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) */ /* Check that the pipe's type matches the endpoint's type */ - if (usb_pipetype(urb->pipe) != pipetypes[xfertype]) + if (usb_urb_ep_type_check(urb)) dev_WARN(&dev->dev, "BOGUS urb xfer, pipe %x != type %x\n", usb_pipetype(urb->pipe), pipetypes[xfertype]); |