]> git.proxmox.com Git - mirror_ubuntu-focal-kernel.git/commitdiff
Merge remote-tracking branches 'asoc/topic/ac97', 'asoc/topic/ac97-mfd', 'asoc/topic...
authorMark Brown <broonie@kernel.org>
Fri, 10 Nov 2017 21:31:02 +0000 (21:31 +0000)
committerMark Brown <broonie@kernel.org>
Fri, 10 Nov 2017 21:31:02 +0000 (21:31 +0000)
43 files changed:
Documentation/devicetree/bindings/mfd/arizona.txt
Documentation/devicetree/bindings/sound/wlf,arizona.txt [new file with mode: 0644]
MAINTAINERS
drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c
drivers/gpu/drm/amd/include/amd_shared.h
drivers/input/touchscreen/Kconfig
drivers/input/touchscreen/wm97xx-core.c
drivers/mfd/Kconfig
drivers/mfd/Makefile
drivers/mfd/arizona-core.c
drivers/mfd/wm97xx-core.c [new file with mode: 0644]
include/drm/amd_asic_type.h [new file with mode: 0644]
include/linux/mfd/arizona/pdata.h
include/linux/mfd/wm97xx.h [new file with mode: 0644]
include/sound/ac97/codec.h [new file with mode: 0644]
include/sound/ac97/compat.h [new file with mode: 0644]
include/sound/ac97/controller.h [new file with mode: 0644]
include/sound/ac97/regs.h [new file with mode: 0644]
include/sound/ac97_codec.h
include/sound/pxa2xx-lib.h
sound/Kconfig
sound/Makefile
sound/ac97/Kconfig [new file with mode: 0644]
sound/ac97/Makefile [new file with mode: 0644]
sound/ac97/ac97_core.h [new file with mode: 0644]
sound/ac97/bus.c [new file with mode: 0644]
sound/ac97/codec.c [new file with mode: 0644]
sound/ac97/snd_ac97_compat.c [new file with mode: 0644]
sound/arm/pxa2xx-ac97-lib.c
sound/arm/pxa2xx-ac97.c
sound/soc/amd/Kconfig
sound/soc/amd/Makefile
sound/soc/amd/acp-pcm-dma.c
sound/soc/amd/acp-rt5645.c [new file with mode: 0644]
sound/soc/amd/acp.h
sound/soc/codecs/arizona.c
sound/soc/codecs/arizona.h
sound/soc/codecs/cs47l24.c
sound/soc/codecs/wm5102.c
sound/soc/codecs/wm5110.c
sound/soc/codecs/wm8997.c
sound/soc/codecs/wm8998.c
sound/soc/pxa/pxa2xx-ac97.c

index b37bdde5cfda3e959887fe5ed434a7a4697a7bdf..bdd017686ea5a082faf99e389b48a624074471cc 100644 (file)
@@ -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:
 
diff --git a/Documentation/devicetree/bindings/sound/wlf,arizona.txt b/Documentation/devicetree/bindings/sound/wlf,arizona.txt
new file mode 100644 (file)
index 0000000..e172c62
--- /dev/null
@@ -0,0 +1,53 @@
+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.
index 2f4e462aa4a214d188bbed5aa612b60b34374448..761aa3c063601f0e427dfd7b472fb5c132f60fa0 100644 (file)
@@ -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
index a52795d9b45852a371fed81a8f17a51d63bab120..ebca22302ebb5e4704e20b7d6301d2fd415f5b48 100644 (file)
@@ -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;
index 70e8c20acb2fd51e63890978483857ef40c4d3b7..3a49fbd8baf88ecd4afb606dc3e8a9681cd59936 100644 (file)
 #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
index 64b30fe273fd7ba17312402c0efc9e81b77e94bb..176b1a74b2b727acf39fd89963a0be070688d75c 100644 (file)
@@ -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
index c9d1c91e1887094f2ef740d9eee3af8d16ee6f82..fd714ee881f73d897b6d9150697f355bc4dd7f6a 100644 (file)
@@ -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);
index fc5e4fef89d222aa587473634bf056d9dee39578..ac5ad6d0837c982de9c3f9e3520d643636eedc81 100644 (file)
@@ -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)
index 8703ff17998e9119d006978dd5ee8c1aeebf5541..0235e6766bc13e070d9c07b39582159787853908 100644 (file)
@@ -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
index 8d46e3ad9529d46a2b2e27229668e517ef38552f..77875250abe590bb73ba2b52ba3c38c444552579 100644 (file)
@@ -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 (file)
index 0000000..4141ee5
--- /dev/null
@@ -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/include/drm/amd_asic_type.h b/include/drm/amd_asic_type.h
new file mode 100644 (file)
index 0000000..599028f
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * 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__ */
index bfeecf179895b09edfb2ed5489e6293ca5a100d7..f72dc53848d705b3d09d57d9df466fb796e51669 100644 (file)
@@ -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];
 
diff --git a/include/linux/mfd/wm97xx.h b/include/linux/mfd/wm97xx.h
new file mode 100644 (file)
index 0000000..45fb54f
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * 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
diff --git a/include/sound/ac97/codec.h b/include/sound/ac97/codec.h
new file mode 100644 (file)
index 0000000..ec04be9
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ *  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
diff --git a/include/sound/ac97/compat.h b/include/sound/ac97/compat.h
new file mode 100644 (file)
index 0000000..1351cba
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ *  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
diff --git a/include/sound/ac97/controller.h b/include/sound/ac97/controller.h
new file mode 100644 (file)
index 0000000..b36ecdd
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ *  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
diff --git a/include/sound/ac97/regs.h b/include/sound/ac97/regs.h
new file mode 100644 (file)
index 0000000..4bb86d3
--- /dev/null
@@ -0,0 +1,262 @@
+/*
+ *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
+ *  Universal interface for Audio Codec '97
+ *
+ *  For more details look to AC '97 component specification revision 2.1
+ *  by Intel Corporation (http://developer.intel.com).
+ *
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ */
+
+/*
+ *  AC'97 codec registers
+ */
+
+#define AC97_RESET             0x00    /* Reset */
+#define AC97_MASTER            0x02    /* Master Volume */
+#define AC97_HEADPHONE         0x04    /* Headphone Volume (optional) */
+#define AC97_MASTER_MONO       0x06    /* Master Volume Mono (optional) */
+#define AC97_MASTER_TONE       0x08    /* Master Tone (Bass & Treble) (optional) */
+#define AC97_PC_BEEP           0x0a    /* PC Beep Volume (optinal) */
+#define AC97_PHONE             0x0c    /* Phone Volume (optional) */
+#define AC97_MIC               0x0e    /* MIC Volume */
+#define AC97_LINE              0x10    /* Line In Volume */
+#define AC97_CD                        0x12    /* CD Volume */
+#define AC97_VIDEO             0x14    /* Video Volume (optional) */
+#define AC97_AUX               0x16    /* AUX Volume (optional) */
+#define AC97_PCM               0x18    /* PCM Volume */
+#define AC97_REC_SEL           0x1a    /* Record Select */
+#define AC97_REC_GAIN          0x1c    /* Record Gain */
+#define AC97_REC_GAIN_MIC      0x1e    /* Record Gain MIC (optional) */
+#define AC97_GENERAL_PURPOSE   0x20    /* General Purpose (optional) */
+#define AC97_3D_CONTROL                0x22    /* 3D Control (optional) */
+#define AC97_INT_PAGING                0x24    /* Audio Interrupt & Paging (AC'97 2.3) */
+#define AC97_POWERDOWN         0x26    /* Powerdown control / status */
+/* range 0x28-0x3a - AUDIO AC'97 2.0 extensions */
+#define AC97_EXTENDED_ID       0x28    /* Extended Audio ID */
+#define AC97_EXTENDED_STATUS   0x2a    /* Extended Audio Status and Control */
+#define AC97_PCM_FRONT_DAC_RATE 0x2c   /* PCM Front DAC Rate */
+#define AC97_PCM_SURR_DAC_RATE 0x2e    /* PCM Surround DAC Rate */
+#define AC97_PCM_LFE_DAC_RATE  0x30    /* PCM LFE DAC Rate */
+#define AC97_PCM_LR_ADC_RATE   0x32    /* PCM LR ADC Rate */
+#define AC97_PCM_MIC_ADC_RATE  0x34    /* PCM MIC ADC Rate */
+#define AC97_CENTER_LFE_MASTER 0x36    /* Center + LFE Master Volume */
+#define AC97_SURROUND_MASTER   0x38    /* Surround (Rear) Master Volume */
+#define AC97_SPDIF             0x3a    /* S/PDIF control */
+/* range 0x3c-0x58 - MODEM */
+#define AC97_EXTENDED_MID      0x3c    /* Extended Modem ID */
+#define AC97_EXTENDED_MSTATUS  0x3e    /* Extended Modem Status and Control */
+#define AC97_LINE1_RATE                0x40    /* Line1 DAC/ADC Rate */
+#define AC97_LINE2_RATE                0x42    /* Line2 DAC/ADC Rate */
+#define AC97_HANDSET_RATE      0x44    /* Handset DAC/ADC Rate */
+#define AC97_LINE1_LEVEL       0x46    /* Line1 DAC/ADC Level */
+#define AC97_LINE2_LEVEL       0x48    /* Line2 DAC/ADC Level */
+#define AC97_HANDSET_LEVEL     0x4a    /* Handset DAC/ADC Level */
+#define AC97_GPIO_CFG          0x4c    /* GPIO Configuration */
+#define AC97_GPIO_POLARITY     0x4e    /* GPIO Pin Polarity/Type, 0=low, 1=high active */
+#define AC97_GPIO_STICKY       0x50    /* GPIO Pin Sticky, 0=not, 1=sticky */
+#define AC97_GPIO_WAKEUP       0x52    /* GPIO Pin Wakeup, 0=no int, 1=yes int */
+#define AC97_GPIO_STATUS       0x54    /* GPIO Pin Status, slot 12 */
+#define AC97_MISC_AFE          0x56    /* Miscellaneous Modem AFE Status and Control */
+/* range 0x5a-0x7b - Vendor Specific */
+#define AC97_VENDOR_ID1                0x7c    /* Vendor ID1 */
+#define AC97_VENDOR_ID2                0x7e    /* Vendor ID2 / revision */
+/* range 0x60-0x6f (page 1) - extended codec registers */
+#define AC97_CODEC_CLASS_REV   0x60    /* Codec Class/Revision */
+#define AC97_PCI_SVID          0x62    /* PCI Subsystem Vendor ID */
+#define AC97_PCI_SID           0x64    /* PCI Subsystem ID */
+#define AC97_FUNC_SELECT       0x66    /* Function Select */
+#define AC97_FUNC_INFO         0x68    /* Function Information */
+#define AC97_SENSE_INFO                0x6a    /* Sense Details */
+
+/* volume controls */
+#define AC97_MUTE_MASK_MONO    0x8000
+#define AC97_MUTE_MASK_STEREO  0x8080
+
+/* slot allocation */
+#define AC97_SLOT_TAG          0
+#define AC97_SLOT_CMD_ADDR     1
+#define AC97_SLOT_CMD_DATA     2
+#define AC97_SLOT_PCM_LEFT     3
+#define AC97_SLOT_PCM_RIGHT    4
+#define AC97_SLOT_MODEM_LINE1  5
+#define AC97_SLOT_PCM_CENTER   6
+#define AC97_SLOT_MIC          6       /* input */
+#define AC97_SLOT_SPDIF_LEFT1  6
+#define AC97_SLOT_PCM_SLEFT    7       /* surround left */
+#define AC97_SLOT_PCM_LEFT_0   7       /* double rate operation */
+#define AC97_SLOT_SPDIF_LEFT   7
+#define AC97_SLOT_PCM_SRIGHT   8       /* surround right */
+#define AC97_SLOT_PCM_RIGHT_0  8       /* double rate operation */
+#define AC97_SLOT_SPDIF_RIGHT  8
+#define AC97_SLOT_LFE          9
+#define AC97_SLOT_SPDIF_RIGHT1 9
+#define AC97_SLOT_MODEM_LINE2  10
+#define AC97_SLOT_PCM_LEFT_1   10      /* double rate operation */
+#define AC97_SLOT_SPDIF_LEFT2  10
+#define AC97_SLOT_HANDSET      11      /* output */
+#define AC97_SLOT_PCM_RIGHT_1  11      /* double rate operation */
+#define AC97_SLOT_SPDIF_RIGHT2 11
+#define AC97_SLOT_MODEM_GPIO   12      /* modem GPIO */
+#define AC97_SLOT_PCM_CENTER_1 12      /* double rate operation */
+
+/* basic capabilities (reset register) */
+#define AC97_BC_DEDICATED_MIC  0x0001  /* Dedicated Mic PCM In Channel */
+#define AC97_BC_RESERVED1      0x0002  /* Reserved (was Modem Line Codec support) */
+#define AC97_BC_BASS_TREBLE    0x0004  /* Bass & Treble Control */
+#define AC97_BC_SIM_STEREO     0x0008  /* Simulated stereo */
+#define AC97_BC_HEADPHONE      0x0010  /* Headphone Out Support */
+#define AC97_BC_LOUDNESS       0x0020  /* Loudness (bass boost) Support */
+#define AC97_BC_16BIT_DAC      0x0000  /* 16-bit DAC resolution */
+#define AC97_BC_18BIT_DAC      0x0040  /* 18-bit DAC resolution */
+#define AC97_BC_20BIT_DAC      0x0080  /* 20-bit DAC resolution */
+#define AC97_BC_DAC_MASK       0x00c0
+#define AC97_BC_16BIT_ADC      0x0000  /* 16-bit ADC resolution */
+#define AC97_BC_18BIT_ADC      0x0100  /* 18-bit ADC resolution */
+#define AC97_BC_20BIT_ADC      0x0200  /* 20-bit ADC resolution */
+#define AC97_BC_ADC_MASK       0x0300
+#define AC97_BC_3D_TECH_ID_MASK        0x7c00  /* Per-vendor ID of 3D enhancement */
+
+/* general purpose */
+#define AC97_GP_DRSS_MASK      0x0c00  /* double rate slot select */
+#define AC97_GP_DRSS_1011      0x0000  /* LR(C) 10+11(+12) */
+#define AC97_GP_DRSS_78                0x0400  /* LR 7+8 */
+
+/* powerdown bits */
+#define AC97_PD_ADC_STATUS     0x0001  /* ADC status (RO) */
+#define AC97_PD_DAC_STATUS     0x0002  /* DAC status (RO) */
+#define AC97_PD_MIXER_STATUS   0x0004  /* Analog mixer status (RO) */
+#define AC97_PD_VREF_STATUS    0x0008  /* Vref status (RO) */
+#define AC97_PD_PR0            0x0100  /* Power down PCM ADCs and input MUX */
+#define AC97_PD_PR1            0x0200  /* Power down PCM front DAC */
+#define AC97_PD_PR2            0x0400  /* Power down Mixer (Vref still on) */
+#define AC97_PD_PR3            0x0800  /* Power down Mixer (Vref off) */
+#define AC97_PD_PR4            0x1000  /* Power down AC-Link */
+#define AC97_PD_PR5            0x2000  /* Disable internal clock usage */
+#define AC97_PD_PR6            0x4000  /* Headphone amplifier */
+#define AC97_PD_EAPD           0x8000  /* External Amplifer Power Down (EAPD) */
+
+/* extended audio ID bit defines */
+#define AC97_EI_VRA            0x0001  /* Variable bit rate supported */
+#define AC97_EI_DRA            0x0002  /* Double rate supported */
+#define AC97_EI_SPDIF          0x0004  /* S/PDIF out supported */
+#define AC97_EI_VRM            0x0008  /* Variable bit rate supported for MIC */
+#define AC97_EI_DACS_SLOT_MASK 0x0030  /* DACs slot assignment */
+#define AC97_EI_DACS_SLOT_SHIFT        4
+#define AC97_EI_CDAC           0x0040  /* PCM Center DAC available */
+#define AC97_EI_SDAC           0x0080  /* PCM Surround DACs available */
+#define AC97_EI_LDAC           0x0100  /* PCM LFE DAC available */
+#define AC97_EI_AMAP           0x0200  /* indicates optional slot/DAC mapping based on codec ID */
+#define AC97_EI_REV_MASK       0x0c00  /* AC'97 revision mask */
+#define AC97_EI_REV_22         0x0400  /* AC'97 revision 2.2 */
+#define AC97_EI_REV_23         0x0800  /* AC'97 revision 2.3 */
+#define AC97_EI_REV_SHIFT      10
+#define AC97_EI_ADDR_MASK      0xc000  /* physical codec ID (address) */
+#define AC97_EI_ADDR_SHIFT     14
+
+/* extended audio status and control bit defines */
+#define AC97_EA_VRA            0x0001  /* Variable bit rate enable bit */
+#define AC97_EA_DRA            0x0002  /* Double-rate audio enable bit */
+#define AC97_EA_SPDIF          0x0004  /* S/PDIF out enable bit */
+#define AC97_EA_VRM            0x0008  /* Variable bit rate for MIC enable bit */
+#define AC97_EA_SPSA_SLOT_MASK 0x0030  /* Mask for slot assignment bits */
+#define AC97_EA_SPSA_SLOT_SHIFT 4
+#define AC97_EA_SPSA_3_4       0x0000  /* Slot assigned to 3 & 4 */
+#define AC97_EA_SPSA_7_8       0x0010  /* Slot assigned to 7 & 8 */
+#define AC97_EA_SPSA_6_9       0x0020  /* Slot assigned to 6 & 9 */
+#define AC97_EA_SPSA_10_11     0x0030  /* Slot assigned to 10 & 11 */
+#define AC97_EA_CDAC           0x0040  /* PCM Center DAC is ready (Read only) */
+#define AC97_EA_SDAC           0x0080  /* PCM Surround DACs are ready (Read only) */
+#define AC97_EA_LDAC           0x0100  /* PCM LFE DAC is ready (Read only) */
+#define AC97_EA_MDAC           0x0200  /* MIC ADC is ready (Read only) */
+#define AC97_EA_SPCV           0x0400  /* S/PDIF configuration valid (Read only) */
+#define AC97_EA_PRI            0x0800  /* Turns the PCM Center DAC off */
+#define AC97_EA_PRJ            0x1000  /* Turns the PCM Surround DACs off */
+#define AC97_EA_PRK            0x2000  /* Turns the PCM LFE DAC off */
+#define AC97_EA_PRL            0x4000  /* Turns the MIC ADC off */
+
+/* S/PDIF control bit defines */
+#define AC97_SC_PRO            0x0001  /* Professional status */
+#define AC97_SC_NAUDIO         0x0002  /* Non audio stream */
+#define AC97_SC_COPY           0x0004  /* Copyright status */
+#define AC97_SC_PRE            0x0008  /* Preemphasis status */
+#define AC97_SC_CC_MASK                0x07f0  /* Category Code mask */
+#define AC97_SC_CC_SHIFT       4
+#define AC97_SC_L              0x0800  /* Generation Level status */
+#define AC97_SC_SPSR_MASK      0x3000  /* S/PDIF Sample Rate bits */
+#define AC97_SC_SPSR_SHIFT     12
+#define AC97_SC_SPSR_44K       0x0000  /* Use 44.1kHz Sample rate */
+#define AC97_SC_SPSR_48K       0x2000  /* Use 48kHz Sample rate */
+#define AC97_SC_SPSR_32K       0x3000  /* Use 32kHz Sample rate */
+#define AC97_SC_DRS            0x4000  /* Double Rate S/PDIF */
+#define AC97_SC_V              0x8000  /* Validity status */
+
+/* Interrupt and Paging bit defines (AC'97 2.3) */
+#define AC97_PAGE_MASK         0x000f  /* Page Selector */
+#define AC97_PAGE_VENDOR       0       /* Vendor-specific registers */
+#define AC97_PAGE_1            1       /* Extended Codec Registers page 1 */
+#define AC97_INT_ENABLE                0x0800  /* Interrupt Enable */
+#define AC97_INT_SENSE         0x1000  /* Sense Cycle */
+#define AC97_INT_CAUSE_SENSE   0x2000  /* Sense Cycle Completed (RO) */
+#define AC97_INT_CAUSE_GPIO    0x4000  /* GPIO bits changed (RO) */
+#define AC97_INT_STATUS                0x8000  /* Interrupt Status */
+
+/* extended modem ID bit defines */
+#define AC97_MEI_LINE1         0x0001  /* Line1 present */
+#define AC97_MEI_LINE2         0x0002  /* Line2 present */
+#define AC97_MEI_HANDSET       0x0004  /* Handset present */
+#define AC97_MEI_CID1          0x0008  /* caller ID decode for Line1 is supported */
+#define AC97_MEI_CID2          0x0010  /* caller ID decode for Line2 is supported */
+#define AC97_MEI_ADDR_MASK     0xc000  /* physical codec ID (address) */
+#define AC97_MEI_ADDR_SHIFT    14
+
+/* extended modem status and control bit defines */
+#define AC97_MEA_GPIO          0x0001  /* GPIO is ready (ro) */
+#define AC97_MEA_MREF          0x0002  /* Vref is up to nominal level (ro) */
+#define AC97_MEA_ADC1          0x0004  /* ADC1 operational (ro) */
+#define AC97_MEA_DAC1          0x0008  /* DAC1 operational (ro) */
+#define AC97_MEA_ADC2          0x0010  /* ADC2 operational (ro) */
+#define AC97_MEA_DAC2          0x0020  /* DAC2 operational (ro) */
+#define AC97_MEA_HADC          0x0040  /* HADC operational (ro) */
+#define AC97_MEA_HDAC          0x0080  /* HDAC operational (ro) */
+#define AC97_MEA_PRA           0x0100  /* GPIO power down (high) */
+#define AC97_MEA_PRB           0x0200  /* reserved */
+#define AC97_MEA_PRC           0x0400  /* ADC1 power down (high) */
+#define AC97_MEA_PRD           0x0800  /* DAC1 power down (high) */
+#define AC97_MEA_PRE           0x1000  /* ADC2 power down (high) */
+#define AC97_MEA_PRF           0x2000  /* DAC2 power down (high) */
+#define AC97_MEA_PRG           0x4000  /* HADC power down (high) */
+#define AC97_MEA_PRH           0x8000  /* HDAC power down (high) */
+
+/* modem gpio status defines */
+#define AC97_GPIO_LINE1_OH      0x0001  /* Off Hook Line1 */
+#define AC97_GPIO_LINE1_RI      0x0002  /* Ring Detect Line1 */
+#define AC97_GPIO_LINE1_CID     0x0004  /* Caller ID path enable Line1 */
+#define AC97_GPIO_LINE1_LCS     0x0008  /* Loop Current Sense Line1 */
+#define AC97_GPIO_LINE1_PULSE   0x0010  /* Opt./ Pulse Dial Line1 (out) */
+#define AC97_GPIO_LINE1_HL1R    0x0020  /* Opt./ Handset to Line1 relay control (out) */
+#define AC97_GPIO_LINE1_HOHD    0x0040  /* Opt./ Handset off hook detect Line1 (in) */
+#define AC97_GPIO_LINE12_AC     0x0080  /* Opt./ Int.bit 1 / Line1/2 AC (out) */
+#define AC97_GPIO_LINE12_DC     0x0100  /* Opt./ Int.bit 2 / Line1/2 DC (out) */
+#define AC97_GPIO_LINE12_RS     0x0200  /* Opt./ Int.bit 3 / Line1/2 RS (out) */
+#define AC97_GPIO_LINE2_OH      0x0400  /* Off Hook Line2 */
+#define AC97_GPIO_LINE2_RI      0x0800  /* Ring Detect Line2 */
+#define AC97_GPIO_LINE2_CID     0x1000  /* Caller ID path enable Line2 */
+#define AC97_GPIO_LINE2_LCS     0x2000  /* Loop Current Sense Line2 */
+#define AC97_GPIO_LINE2_PULSE   0x4000  /* Opt./ Pulse Dial Line2 (out) */
+#define AC97_GPIO_LINE2_HL1R    0x8000  /* Opt./ Handset to Line2 relay control (out) */
+
index 15aa5f07c955bed7f6b0d7f1dfc9471d7f229120..89d311a503d34802223b98dbb4e80c924afee0b8 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/bitops.h>
 #include <linux/device.h>
 #include <linux/workqueue.h>
+#include <sound/ac97/regs.h>
 #include <sound/pcm.h>
 #include <sound/control.h>
 #include <sound/info.h>
 /* maximum number of devices on the AC97 bus */
 #define        AC97_BUS_MAX_DEVICES    4
 
-/*
- *  AC'97 codec registers
- */
-
-#define AC97_RESET             0x00    /* Reset */
-#define AC97_MASTER            0x02    /* Master Volume */
-#define AC97_HEADPHONE         0x04    /* Headphone Volume (optional) */
-#define AC97_MASTER_MONO       0x06    /* Master Volume Mono (optional) */
-#define AC97_MASTER_TONE       0x08    /* Master Tone (Bass & Treble) (optional) */
-#define AC97_PC_BEEP           0x0a    /* PC Beep Volume (optinal) */
-#define AC97_PHONE             0x0c    /* Phone Volume (optional) */
-#define AC97_MIC               0x0e    /* MIC Volume */
-#define AC97_LINE              0x10    /* Line In Volume */
-#define AC97_CD                        0x12    /* CD Volume */
-#define AC97_VIDEO             0x14    /* Video Volume (optional) */
-#define AC97_AUX               0x16    /* AUX Volume (optional) */
-#define AC97_PCM               0x18    /* PCM Volume */
-#define AC97_REC_SEL           0x1a    /* Record Select */
-#define AC97_REC_GAIN          0x1c    /* Record Gain */
-#define AC97_REC_GAIN_MIC      0x1e    /* Record Gain MIC (optional) */
-#define AC97_GENERAL_PURPOSE   0x20    /* General Purpose (optional) */
-#define AC97_3D_CONTROL                0x22    /* 3D Control (optional) */
-#define AC97_INT_PAGING                0x24    /* Audio Interrupt & Paging (AC'97 2.3) */
-#define AC97_POWERDOWN         0x26    /* Powerdown control / status */
-/* range 0x28-0x3a - AUDIO AC'97 2.0 extensions */
-#define AC97_EXTENDED_ID       0x28    /* Extended Audio ID */
-#define AC97_EXTENDED_STATUS   0x2a    /* Extended Audio Status and Control */
-#define AC97_PCM_FRONT_DAC_RATE 0x2c   /* PCM Front DAC Rate */
-#define AC97_PCM_SURR_DAC_RATE 0x2e    /* PCM Surround DAC Rate */
-#define AC97_PCM_LFE_DAC_RATE  0x30    /* PCM LFE DAC Rate */
-#define AC97_PCM_LR_ADC_RATE   0x32    /* PCM LR ADC Rate */
-#define AC97_PCM_MIC_ADC_RATE  0x34    /* PCM MIC ADC Rate */
-#define AC97_CENTER_LFE_MASTER 0x36    /* Center + LFE Master Volume */
-#define AC97_SURROUND_MASTER   0x38    /* Surround (Rear) Master Volume */
-#define AC97_SPDIF             0x3a    /* S/PDIF control */
-/* range 0x3c-0x58 - MODEM */
-#define AC97_EXTENDED_MID      0x3c    /* Extended Modem ID */
-#define AC97_EXTENDED_MSTATUS  0x3e    /* Extended Modem Status and Control */
-#define AC97_LINE1_RATE                0x40    /* Line1 DAC/ADC Rate */
-#define AC97_LINE2_RATE                0x42    /* Line2 DAC/ADC Rate */
-#define AC97_HANDSET_RATE      0x44    /* Handset DAC/ADC Rate */
-#define AC97_LINE1_LEVEL       0x46    /* Line1 DAC/ADC Level */
-#define AC97_LINE2_LEVEL       0x48    /* Line2 DAC/ADC Level */
-#define AC97_HANDSET_LEVEL     0x4a    /* Handset DAC/ADC Level */
-#define AC97_GPIO_CFG          0x4c    /* GPIO Configuration */
-#define AC97_GPIO_POLARITY     0x4e    /* GPIO Pin Polarity/Type, 0=low, 1=high active */
-#define AC97_GPIO_STICKY       0x50    /* GPIO Pin Sticky, 0=not, 1=sticky */
-#define AC97_GPIO_WAKEUP       0x52    /* GPIO Pin Wakeup, 0=no int, 1=yes int */
-#define AC97_GPIO_STATUS       0x54    /* GPIO Pin Status, slot 12 */
-#define AC97_MISC_AFE          0x56    /* Miscellaneous Modem AFE Status and Control */
-/* range 0x5a-0x7b - Vendor Specific */
-#define AC97_VENDOR_ID1                0x7c    /* Vendor ID1 */
-#define AC97_VENDOR_ID2                0x7e    /* Vendor ID2 / revision */
-/* range 0x60-0x6f (page 1) - extended codec registers */
-#define AC97_CODEC_CLASS_REV   0x60    /* Codec Class/Revision */
-#define AC97_PCI_SVID          0x62    /* PCI Subsystem Vendor ID */
-#define AC97_PCI_SID           0x64    /* PCI Subsystem ID */
-#define AC97_FUNC_SELECT       0x66    /* Function Select */
-#define AC97_FUNC_INFO         0x68    /* Function Information */
-#define AC97_SENSE_INFO                0x6a    /* Sense Details */
-
-/* volume controls */
-#define AC97_MUTE_MASK_MONO    0x8000
-#define AC97_MUTE_MASK_STEREO  0x8080
-
-/* slot allocation */
-#define AC97_SLOT_TAG          0
-#define AC97_SLOT_CMD_ADDR     1
-#define AC97_SLOT_CMD_DATA     2
-#define AC97_SLOT_PCM_LEFT     3
-#define AC97_SLOT_PCM_RIGHT    4
-#define AC97_SLOT_MODEM_LINE1  5
-#define AC97_SLOT_PCM_CENTER   6
-#define AC97_SLOT_MIC          6       /* input */
-#define AC97_SLOT_SPDIF_LEFT1  6
-#define AC97_SLOT_PCM_SLEFT    7       /* surround left */
-#define AC97_SLOT_PCM_LEFT_0   7       /* double rate operation */
-#define AC97_SLOT_SPDIF_LEFT   7
-#define AC97_SLOT_PCM_SRIGHT   8       /* surround right */
-#define AC97_SLOT_PCM_RIGHT_0  8       /* double rate operation */
-#define AC97_SLOT_SPDIF_RIGHT  8
-#define AC97_SLOT_LFE          9
-#define AC97_SLOT_SPDIF_RIGHT1 9
-#define AC97_SLOT_MODEM_LINE2  10
-#define AC97_SLOT_PCM_LEFT_1   10      /* double rate operation */
-#define AC97_SLOT_SPDIF_LEFT2  10
-#define AC97_SLOT_HANDSET      11      /* output */
-#define AC97_SLOT_PCM_RIGHT_1  11      /* double rate operation */
-#define AC97_SLOT_SPDIF_RIGHT2 11
-#define AC97_SLOT_MODEM_GPIO   12      /* modem GPIO */
-#define AC97_SLOT_PCM_CENTER_1 12      /* double rate operation */
-
-/* basic capabilities (reset register) */
-#define AC97_BC_DEDICATED_MIC  0x0001  /* Dedicated Mic PCM In Channel */
-#define AC97_BC_RESERVED1      0x0002  /* Reserved (was Modem Line Codec support) */
-#define AC97_BC_BASS_TREBLE    0x0004  /* Bass & Treble Control */
-#define AC97_BC_SIM_STEREO     0x0008  /* Simulated stereo */
-#define AC97_BC_HEADPHONE      0x0010  /* Headphone Out Support */
-#define AC97_BC_LOUDNESS       0x0020  /* Loudness (bass boost) Support */
-#define AC97_BC_16BIT_DAC      0x0000  /* 16-bit DAC resolution */
-#define AC97_BC_18BIT_DAC      0x0040  /* 18-bit DAC resolution */
-#define AC97_BC_20BIT_DAC      0x0080  /* 20-bit DAC resolution */
-#define AC97_BC_DAC_MASK       0x00c0
-#define AC97_BC_16BIT_ADC      0x0000  /* 16-bit ADC resolution */
-#define AC97_BC_18BIT_ADC      0x0100  /* 18-bit ADC resolution */
-#define AC97_BC_20BIT_ADC      0x0200  /* 20-bit ADC resolution */
-#define AC97_BC_ADC_MASK       0x0300
-#define AC97_BC_3D_TECH_ID_MASK        0x7c00  /* Per-vendor ID of 3D enhancement */
-
-/* general purpose */
-#define AC97_GP_DRSS_MASK      0x0c00  /* double rate slot select */
-#define AC97_GP_DRSS_1011      0x0000  /* LR(C) 10+11(+12) */
-#define AC97_GP_DRSS_78                0x0400  /* LR 7+8 */
-
-/* powerdown bits */
-#define AC97_PD_ADC_STATUS     0x0001  /* ADC status (RO) */
-#define AC97_PD_DAC_STATUS     0x0002  /* DAC status (RO) */
-#define AC97_PD_MIXER_STATUS   0x0004  /* Analog mixer status (RO) */
-#define AC97_PD_VREF_STATUS    0x0008  /* Vref status (RO) */
-#define AC97_PD_PR0            0x0100  /* Power down PCM ADCs and input MUX */
-#define AC97_PD_PR1            0x0200  /* Power down PCM front DAC */
-#define AC97_PD_PR2            0x0400  /* Power down Mixer (Vref still on) */
-#define AC97_PD_PR3            0x0800  /* Power down Mixer (Vref off) */
-#define AC97_PD_PR4            0x1000  /* Power down AC-Link */
-#define AC97_PD_PR5            0x2000  /* Disable internal clock usage */
-#define AC97_PD_PR6            0x4000  /* Headphone amplifier */
-#define AC97_PD_EAPD           0x8000  /* External Amplifer Power Down (EAPD) */
-
-/* extended audio ID bit defines */
-#define AC97_EI_VRA            0x0001  /* Variable bit rate supported */
-#define AC97_EI_DRA            0x0002  /* Double rate supported */
-#define AC97_EI_SPDIF          0x0004  /* S/PDIF out supported */
-#define AC97_EI_VRM            0x0008  /* Variable bit rate supported for MIC */
-#define AC97_EI_DACS_SLOT_MASK 0x0030  /* DACs slot assignment */
-#define AC97_EI_DACS_SLOT_SHIFT        4
-#define AC97_EI_CDAC           0x0040  /* PCM Center DAC available */
-#define AC97_EI_SDAC           0x0080  /* PCM Surround DACs available */
-#define AC97_EI_LDAC           0x0100  /* PCM LFE DAC available */
-#define AC97_EI_AMAP           0x0200  /* indicates optional slot/DAC mapping based on codec ID */
-#define AC97_EI_REV_MASK       0x0c00  /* AC'97 revision mask */
-#define AC97_EI_REV_22         0x0400  /* AC'97 revision 2.2 */
-#define AC97_EI_REV_23         0x0800  /* AC'97 revision 2.3 */
-#define AC97_EI_REV_SHIFT      10
-#define AC97_EI_ADDR_MASK      0xc000  /* physical codec ID (address) */
-#define AC97_EI_ADDR_SHIFT     14
-
-/* extended audio status and control bit defines */
-#define AC97_EA_VRA            0x0001  /* Variable bit rate enable bit */
-#define AC97_EA_DRA            0x0002  /* Double-rate audio enable bit */
-#define AC97_EA_SPDIF          0x0004  /* S/PDIF out enable bit */
-#define AC97_EA_VRM            0x0008  /* Variable bit rate for MIC enable bit */
-#define AC97_EA_SPSA_SLOT_MASK 0x0030  /* Mask for slot assignment bits */
-#define AC97_EA_SPSA_SLOT_SHIFT 4
-#define AC97_EA_SPSA_3_4       0x0000  /* Slot assigned to 3 & 4 */
-#define AC97_EA_SPSA_7_8       0x0010  /* Slot assigned to 7 & 8 */
-#define AC97_EA_SPSA_6_9       0x0020  /* Slot assigned to 6 & 9 */
-#define AC97_EA_SPSA_10_11     0x0030  /* Slot assigned to 10 & 11 */
-#define AC97_EA_CDAC           0x0040  /* PCM Center DAC is ready (Read only) */
-#define AC97_EA_SDAC           0x0080  /* PCM Surround DACs are ready (Read only) */
-#define AC97_EA_LDAC           0x0100  /* PCM LFE DAC is ready (Read only) */
-#define AC97_EA_MDAC           0x0200  /* MIC ADC is ready (Read only) */
-#define AC97_EA_SPCV           0x0400  /* S/PDIF configuration valid (Read only) */
-#define AC97_EA_PRI            0x0800  /* Turns the PCM Center DAC off */
-#define AC97_EA_PRJ            0x1000  /* Turns the PCM Surround DACs off */
-#define AC97_EA_PRK            0x2000  /* Turns the PCM LFE DAC off */
-#define AC97_EA_PRL            0x4000  /* Turns the MIC ADC off */
-
-/* S/PDIF control bit defines */
-#define AC97_SC_PRO            0x0001  /* Professional status */
-#define AC97_SC_NAUDIO         0x0002  /* Non audio stream */
-#define AC97_SC_COPY           0x0004  /* Copyright status */
-#define AC97_SC_PRE            0x0008  /* Preemphasis status */
-#define AC97_SC_CC_MASK                0x07f0  /* Category Code mask */
-#define AC97_SC_CC_SHIFT       4
-#define AC97_SC_L              0x0800  /* Generation Level status */
-#define AC97_SC_SPSR_MASK      0x3000  /* S/PDIF Sample Rate bits */
-#define AC97_SC_SPSR_SHIFT     12
-#define AC97_SC_SPSR_44K       0x0000  /* Use 44.1kHz Sample rate */
-#define AC97_SC_SPSR_48K       0x2000  /* Use 48kHz Sample rate */
-#define AC97_SC_SPSR_32K       0x3000  /* Use 32kHz Sample rate */
-#define AC97_SC_DRS            0x4000  /* Double Rate S/PDIF */
-#define AC97_SC_V              0x8000  /* Validity status */
-
-/* Interrupt and Paging bit defines (AC'97 2.3) */
-#define AC97_PAGE_MASK         0x000f  /* Page Selector */
-#define AC97_PAGE_VENDOR       0       /* Vendor-specific registers */
-#define AC97_PAGE_1            1       /* Extended Codec Registers page 1 */
-#define AC97_INT_ENABLE                0x0800  /* Interrupt Enable */
-#define AC97_INT_SENSE         0x1000  /* Sense Cycle */
-#define AC97_INT_CAUSE_SENSE   0x2000  /* Sense Cycle Completed (RO) */
-#define AC97_INT_CAUSE_GPIO    0x4000  /* GPIO bits changed (RO) */
-#define AC97_INT_STATUS                0x8000  /* Interrupt Status */
-
-/* extended modem ID bit defines */
-#define AC97_MEI_LINE1         0x0001  /* Line1 present */
-#define AC97_MEI_LINE2         0x0002  /* Line2 present */
-#define AC97_MEI_HANDSET       0x0004  /* Handset present */
-#define AC97_MEI_CID1          0x0008  /* caller ID decode for Line1 is supported */
-#define AC97_MEI_CID2          0x0010  /* caller ID decode for Line2 is supported */
-#define AC97_MEI_ADDR_MASK     0xc000  /* physical codec ID (address) */
-#define AC97_MEI_ADDR_SHIFT    14
-
-/* extended modem status and control bit defines */
-#define AC97_MEA_GPIO          0x0001  /* GPIO is ready (ro) */
-#define AC97_MEA_MREF          0x0002  /* Vref is up to nominal level (ro) */
-#define AC97_MEA_ADC1          0x0004  /* ADC1 operational (ro) */
-#define AC97_MEA_DAC1          0x0008  /* DAC1 operational (ro) */
-#define AC97_MEA_ADC2          0x0010  /* ADC2 operational (ro) */
-#define AC97_MEA_DAC2          0x0020  /* DAC2 operational (ro) */
-#define AC97_MEA_HADC          0x0040  /* HADC operational (ro) */
-#define AC97_MEA_HDAC          0x0080  /* HDAC operational (ro) */
-#define AC97_MEA_PRA           0x0100  /* GPIO power down (high) */
-#define AC97_MEA_PRB           0x0200  /* reserved */
-#define AC97_MEA_PRC           0x0400  /* ADC1 power down (high) */
-#define AC97_MEA_PRD           0x0800  /* DAC1 power down (high) */
-#define AC97_MEA_PRE           0x1000  /* ADC2 power down (high) */
-#define AC97_MEA_PRF           0x2000  /* DAC2 power down (high) */
-#define AC97_MEA_PRG           0x4000  /* HADC power down (high) */
-#define AC97_MEA_PRH           0x8000  /* HDAC power down (high) */
-
-/* modem gpio status defines */
-#define AC97_GPIO_LINE1_OH      0x0001  /* Off Hook Line1 */
-#define AC97_GPIO_LINE1_RI      0x0002  /* Ring Detect Line1 */
-#define AC97_GPIO_LINE1_CID     0x0004  /* Caller ID path enable Line1 */
-#define AC97_GPIO_LINE1_LCS     0x0008  /* Loop Current Sense Line1 */
-#define AC97_GPIO_LINE1_PULSE   0x0010  /* Opt./ Pulse Dial Line1 (out) */
-#define AC97_GPIO_LINE1_HL1R    0x0020  /* Opt./ Handset to Line1 relay control (out) */
-#define AC97_GPIO_LINE1_HOHD    0x0040  /* Opt./ Handset off hook detect Line1 (in) */
-#define AC97_GPIO_LINE12_AC     0x0080  /* Opt./ Int.bit 1 / Line1/2 AC (out) */
-#define AC97_GPIO_LINE12_DC     0x0100  /* Opt./ Int.bit 2 / Line1/2 DC (out) */
-#define AC97_GPIO_LINE12_RS     0x0200  /* Opt./ Int.bit 3 / Line1/2 RS (out) */
-#define AC97_GPIO_LINE2_OH      0x0400  /* Off Hook Line2 */
-#define AC97_GPIO_LINE2_RI      0x0800  /* Ring Detect Line2 */
-#define AC97_GPIO_LINE2_CID     0x1000  /* Caller ID path enable Line2 */
-#define AC97_GPIO_LINE2_LCS     0x2000  /* Loop Current Sense Line2 */
-#define AC97_GPIO_LINE2_PULSE   0x4000  /* Opt./ Pulse Dial Line2 (out) */
-#define AC97_GPIO_LINE2_HL1R    0x8000  /* Opt./ Handset to Line2 relay control (out) */
-
 /* specific - SigmaTel */
 #define AC97_SIGMATEL_OUTSEL   0x64    /* Output Select, STAC9758 */
 #define AC97_SIGMATEL_INSEL    0x66    /* Input Select, STAC9758 */
index 5e710d848bd33262bb67100ce4b0e58a3d61d4a3..63f75450d3dbb9f09eb9c11a1984c6a1c8e8fea2 100644 (file)
@@ -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);
index d7d2aac9542ea5923e82e5ee7a379fd5ae7383f9..ed34218d38b80152609b5bfbc144d0be99f1215d 100644 (file)
@@ -80,6 +80,8 @@ source "sound/hda/Kconfig"
 
 source "sound/ppc/Kconfig"
 
+source "sound/ac97/Kconfig"
+
 source "sound/aoa/Kconfig"
 
 source "sound/arm/Kconfig"
index f2d1d093bcdce876151e1762967c9ba76d1771a2..f245c75a2add973670085e1cfd85031987066e85 100644 (file)
@@ -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
diff --git a/sound/ac97/Kconfig b/sound/ac97/Kconfig
new file mode 100644 (file)
index 0000000..f8a64e1
--- /dev/null
@@ -0,0 +1,19 @@
+#
+# 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
diff --git a/sound/ac97/Makefile b/sound/ac97/Makefile
new file mode 100644 (file)
index 0000000..f9c2640
--- /dev/null
@@ -0,0 +1,8 @@
+#
+# 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
diff --git a/sound/ac97/ac97_core.h b/sound/ac97/ac97_core.h
new file mode 100644 (file)
index 0000000..08441a4
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * 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);
+}
diff --git a/sound/ac97/bus.c b/sound/ac97/bus.c
new file mode 100644 (file)
index 0000000..31f858e
--- /dev/null
@@ -0,0 +1,539 @@
+/*
+ * 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/module.h>
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/idr.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <sound/ac97/codec.h>
+#include <sound/ac97/controller.h>
+#include <sound/ac97/regs.h>
+
+#include "ac97_core.h"
+
+/*
+ * Protects ac97_controllers and each ac97_controller structure.
+ */
+static DEFINE_MUTEX(ac97_controllers_mutex);
+static DEFINE_IDR(ac97_adapter_idr);
+static LIST_HEAD(ac97_controllers);
+
+static struct bus_type ac97_bus_type;
+
+static inline struct ac97_controller*
+to_ac97_controller(struct device *ac97_adapter)
+{
+       return container_of(ac97_adapter, struct ac97_controller, adap);
+}
+
+static int ac97_unbound_ctrl_write(struct ac97_controller *adrv, int slot,
+                    unsigned short reg, unsigned short val)
+{
+       return -ENODEV;
+}
+
+static int ac97_unbound_ctrl_read(struct ac97_controller *adrv, int slot,
+                                 unsigned short reg)
+{
+       return -ENODEV;
+}
+
+static const struct ac97_controller_ops ac97_unbound_ctrl_ops = {
+       .write = ac97_unbound_ctrl_write,
+       .read = ac97_unbound_ctrl_read,
+};
+
+static struct ac97_controller ac97_unbound_ctrl = {
+       .ops = &ac97_unbound_ctrl_ops,
+};
+
+static struct ac97_codec_device *
+ac97_codec_find(struct ac97_controller *ac97_ctrl, unsigned int codec_num)
+{
+       if (codec_num >= AC97_BUS_MAX_CODECS)
+               return ERR_PTR(-EINVAL);
+
+       return ac97_ctrl->codecs[codec_num];
+}
+
+static void ac97_codec_release(struct device *dev)
+{
+       struct ac97_codec_device *adev;
+       struct ac97_controller *ac97_ctrl;
+
+       adev = to_ac97_device(dev);
+       ac97_ctrl = adev->ac97_ctrl;
+       ac97_ctrl->codecs[adev->num] = NULL;
+       kfree(adev);
+}
+
+static int ac97_codec_add(struct ac97_controller *ac97_ctrl, int idx,
+                  unsigned int vendor_id)
+{
+       struct ac97_codec_device *codec;
+       int ret;
+
+       codec = kzalloc(sizeof(*codec), GFP_KERNEL);
+       if (!codec)
+               return -ENOMEM;
+       ac97_ctrl->codecs[idx] = codec;
+       codec->vendor_id = vendor_id;
+       codec->dev.release = ac97_codec_release;
+       codec->dev.bus = &ac97_bus_type;
+       codec->dev.parent = &ac97_ctrl->adap;
+       codec->num = idx;
+       codec->ac97_ctrl = ac97_ctrl;
+
+       device_initialize(&codec->dev);
+       dev_set_name(&codec->dev, "%s:%u", dev_name(ac97_ctrl->parent), idx);
+
+       ret = device_add(&codec->dev);
+       if (ret)
+               goto err_free_codec;
+
+       return 0;
+err_free_codec:
+       put_device(&codec->dev);
+       kfree(codec);
+       ac97_ctrl->codecs[idx] = NULL;
+
+       return ret;
+}
+
+unsigned int snd_ac97_bus_scan_one(struct ac97_controller *adrv,
+                                  unsigned int codec_num)
+{
+       unsigned short vid1, vid2;
+       int ret;
+
+       ret = adrv->ops->read(adrv, codec_num, AC97_VENDOR_ID1);
+       vid1 = (ret & 0xffff);
+       if (ret < 0)
+               return 0;
+
+       ret = adrv->ops->read(adrv, codec_num, AC97_VENDOR_ID2);
+       vid2 = (ret & 0xffff);
+       if (ret < 0)
+               return 0;
+
+       dev_dbg(&adrv->adap, "%s(codec_num=%u): vendor_id=0x%08x\n",
+               __func__, codec_num, AC97_ID(vid1, vid2));
+       return AC97_ID(vid1, vid2);
+}
+
+static int ac97_bus_scan(struct ac97_controller *ac97_ctrl)
+{
+       int ret, i;
+       unsigned int vendor_id;
+
+       for (i = 0; i < AC97_BUS_MAX_CODECS; i++) {
+               if (ac97_codec_find(ac97_ctrl, i))
+                       continue;
+               if (!(ac97_ctrl->slots_available & BIT(i)))
+                       continue;
+               vendor_id = snd_ac97_bus_scan_one(ac97_ctrl, i);
+               if (!vendor_id)
+                       continue;
+
+               ret = ac97_codec_add(ac97_ctrl, i, vendor_id);
+               if (ret < 0)
+                       return ret;
+       }
+       return 0;
+}
+
+static int ac97_bus_reset(struct ac97_controller *ac97_ctrl)
+{
+       ac97_ctrl->ops->reset(ac97_ctrl);
+
+       return 0;
+}
+
+/**
+ * snd_ac97_codec_driver_register - register an AC97 codec driver
+ * @dev: AC97 driver codec to register
+ *
+ * Register an AC97 codec driver to the ac97 bus driver, aka. the AC97 digital
+ * controller.
+ *
+ * Returns 0 on success or error code
+ */
+int snd_ac97_codec_driver_register(struct ac97_codec_driver *drv)
+{
+       drv->driver.bus = &ac97_bus_type;
+       return driver_register(&drv->driver);
+}
+EXPORT_SYMBOL_GPL(snd_ac97_codec_driver_register);
+
+/**
+ * snd_ac97_codec_driver_unregister - unregister an AC97 codec driver
+ * @dev: AC97 codec driver to unregister
+ *
+ * Unregister a previously registered ac97 codec driver.
+ */
+void snd_ac97_codec_driver_unregister(struct ac97_codec_driver *drv)
+{
+       driver_unregister(&drv->driver);
+}
+EXPORT_SYMBOL_GPL(snd_ac97_codec_driver_unregister);
+
+/**
+ * snd_ac97_codec_get_platdata - get platform_data
+ * @adev: the ac97 codec device
+ *
+ * For legacy platforms, in order to have platform_data in codec drivers
+ * available, while ac97 device are auto-created upon probe, this retrieves the
+ * platdata which was setup on ac97 controller registration.
+ *
+ * Returns the platform data pointer
+ */
+void *snd_ac97_codec_get_platdata(const struct ac97_codec_device *adev)
+{
+       struct ac97_controller *ac97_ctrl = adev->ac97_ctrl;
+
+       return ac97_ctrl->codecs_pdata[adev->num];
+}
+EXPORT_SYMBOL_GPL(snd_ac97_codec_get_platdata);
+
+static void ac97_ctrl_codecs_unregister(struct ac97_controller *ac97_ctrl)
+{
+       int i;
+
+       for (i = 0; i < AC97_BUS_MAX_CODECS; i++)
+               if (ac97_ctrl->codecs[i]) {
+                       ac97_ctrl->codecs[i]->ac97_ctrl = &ac97_unbound_ctrl;
+                       device_unregister(&ac97_ctrl->codecs[i]->dev);
+               }
+}
+
+static ssize_t cold_reset_store(struct device *dev,
+                               struct device_attribute *attr, const char *buf,
+                               size_t len)
+{
+       struct ac97_controller *ac97_ctrl;
+
+       mutex_lock(&ac97_controllers_mutex);
+       ac97_ctrl = to_ac97_controller(dev);
+       ac97_ctrl->ops->reset(ac97_ctrl);
+       mutex_unlock(&ac97_controllers_mutex);
+       return len;
+}
+static DEVICE_ATTR_WO(cold_reset);
+
+static ssize_t warm_reset_store(struct device *dev,
+                               struct device_attribute *attr, const char *buf,
+                               size_t len)
+{
+       struct ac97_controller *ac97_ctrl;
+
+       if (!dev)
+               return -ENODEV;
+
+       mutex_lock(&ac97_controllers_mutex);
+       ac97_ctrl = to_ac97_controller(dev);
+       ac97_ctrl->ops->warm_reset(ac97_ctrl);
+       mutex_unlock(&ac97_controllers_mutex);
+       return len;
+}
+static DEVICE_ATTR_WO(warm_reset);
+
+static struct attribute *ac97_controller_device_attrs[] = {
+       &dev_attr_cold_reset.attr,
+       &dev_attr_warm_reset.attr,
+       NULL
+};
+
+static struct attribute_group ac97_adapter_attr_group = {
+       .name   = "ac97_operations",
+       .attrs  = ac97_controller_device_attrs,
+};
+
+static const struct attribute_group *ac97_adapter_groups[] = {
+       &ac97_adapter_attr_group,
+       NULL,
+};
+
+static void ac97_del_adapter(struct ac97_controller *ac97_ctrl)
+{
+       mutex_lock(&ac97_controllers_mutex);
+       ac97_ctrl_codecs_unregister(ac97_ctrl);
+       list_del(&ac97_ctrl->controllers);
+       mutex_unlock(&ac97_controllers_mutex);
+
+       device_unregister(&ac97_ctrl->adap);
+}
+
+static void ac97_adapter_release(struct device *dev)
+{
+       struct ac97_controller *ac97_ctrl;
+
+       ac97_ctrl = to_ac97_controller(dev);
+       idr_remove(&ac97_adapter_idr, ac97_ctrl->nr);
+       dev_dbg(&ac97_ctrl->adap, "adapter unregistered by %s\n",
+               dev_name(ac97_ctrl->parent));
+}
+
+static const struct device_type ac97_adapter_type = {
+       .groups         = ac97_adapter_groups,
+       .release        = ac97_adapter_release,
+};
+
+static int ac97_add_adapter(struct ac97_controller *ac97_ctrl)
+{
+       int ret;
+
+       mutex_lock(&ac97_controllers_mutex);
+       ret = idr_alloc(&ac97_adapter_idr, ac97_ctrl, 0, 0, GFP_KERNEL);
+       ac97_ctrl->nr = ret;
+       if (ret >= 0) {
+               dev_set_name(&ac97_ctrl->adap, "ac97-%d", ret);
+               ac97_ctrl->adap.type = &ac97_adapter_type;
+               ac97_ctrl->adap.parent = ac97_ctrl->parent;
+               ret = device_register(&ac97_ctrl->adap);
+               if (ret)
+                       put_device(&ac97_ctrl->adap);
+       }
+       if (!ret)
+               list_add(&ac97_ctrl->controllers, &ac97_controllers);
+       mutex_unlock(&ac97_controllers_mutex);
+
+       if (!ret)
+               dev_dbg(&ac97_ctrl->adap, "adapter registered by %s\n",
+                       dev_name(ac97_ctrl->parent));
+       return ret;
+}
+
+/**
+ * snd_ac97_controller_register - register an ac97 controller
+ * @ops: the ac97 bus operations
+ * @dev: the device providing the ac97 DC function
+ * @slots_available: mask of the ac97 codecs that can be scanned and probed
+ *                   bit0 => codec 0, bit1 => codec 1 ... bit 3 => codec 3
+ *
+ * Register a digital controller which can control up to 4 ac97 codecs. This is
+ * the controller side of the AC97 AC-link, while the slave side are the codecs.
+ *
+ * Returns a valid controller upon success, negative pointer value upon error
+ */
+struct ac97_controller *snd_ac97_controller_register(
+       const struct ac97_controller_ops *ops, struct device *dev,
+       unsigned short slots_available, void **codecs_pdata)
+{
+       struct ac97_controller *ac97_ctrl;
+       int ret, i;
+
+       ac97_ctrl = kzalloc(sizeof(*ac97_ctrl), GFP_KERNEL);
+       if (!ac97_ctrl)
+               return ERR_PTR(-ENOMEM);
+
+       for (i = 0; i < AC97_BUS_MAX_CODECS && codecs_pdata; i++)
+               ac97_ctrl->codecs_pdata[i] = codecs_pdata[i];
+
+       ac97_ctrl->ops = ops;
+       ac97_ctrl->slots_available = slots_available;
+       ac97_ctrl->parent = dev;
+       ret = ac97_add_adapter(ac97_ctrl);
+
+       if (ret)
+               goto err;
+       ac97_bus_reset(ac97_ctrl);
+       ac97_bus_scan(ac97_ctrl);
+
+       return ac97_ctrl;
+err:
+       kfree(ac97_ctrl);
+       return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(snd_ac97_controller_register);
+
+/**
+ * snd_ac97_controller_unregister - unregister an ac97 controller
+ * @ac97_ctrl: the device previously provided to ac97_controller_register()
+ *
+ */
+void snd_ac97_controller_unregister(struct ac97_controller *ac97_ctrl)
+{
+       ac97_del_adapter(ac97_ctrl);
+}
+EXPORT_SYMBOL_GPL(snd_ac97_controller_unregister);
+
+#ifdef CONFIG_PM
+static int ac97_pm_runtime_suspend(struct device *dev)
+{
+       struct ac97_codec_device *codec = to_ac97_device(dev);
+       int ret = pm_generic_runtime_suspend(dev);
+
+       if (ret == 0 && dev->driver) {
+               if (pm_runtime_is_irq_safe(dev))
+                       clk_disable(codec->clk);
+               else
+                       clk_disable_unprepare(codec->clk);
+       }
+
+       return ret;
+}
+
+static int ac97_pm_runtime_resume(struct device *dev)
+{
+       struct ac97_codec_device *codec = to_ac97_device(dev);
+       int ret;
+
+       if (dev->driver) {
+               if (pm_runtime_is_irq_safe(dev))
+                       ret = clk_enable(codec->clk);
+               else
+                       ret = clk_prepare_enable(codec->clk);
+               if (ret)
+                       return ret;
+       }
+
+       return pm_generic_runtime_resume(dev);
+}
+#endif /* CONFIG_PM */
+
+static const struct dev_pm_ops ac97_pm = {
+       .suspend        = pm_generic_suspend,
+       .resume         = pm_generic_resume,
+       .freeze         = pm_generic_freeze,
+       .thaw           = pm_generic_thaw,
+       .poweroff       = pm_generic_poweroff,
+       .restore        = pm_generic_restore,
+       SET_RUNTIME_PM_OPS(
+               ac97_pm_runtime_suspend,
+               ac97_pm_runtime_resume,
+               NULL)
+};
+
+static int ac97_get_enable_clk(struct ac97_codec_device *adev)
+{
+       int ret;
+
+       adev->clk = clk_get(&adev->dev, "ac97_clk");
+       if (IS_ERR(adev->clk))
+               return PTR_ERR(adev->clk);
+
+       ret = clk_prepare_enable(adev->clk);
+       if (ret)
+               clk_put(adev->clk);
+
+       return ret;
+}
+
+static void ac97_put_disable_clk(struct ac97_codec_device *adev)
+{
+       clk_disable_unprepare(adev->clk);
+       clk_put(adev->clk);
+}
+
+static ssize_t vendor_id_show(struct device *dev,
+                             struct device_attribute *attr, char *buf)
+{
+       struct ac97_codec_device *codec = to_ac97_device(dev);
+
+       return sprintf(buf, "%08x", codec->vendor_id);
+}
+DEVICE_ATTR_RO(vendor_id);
+
+static struct attribute *ac97_dev_attrs[] = {
+       &dev_attr_vendor_id.attr,
+       NULL,
+};
+ATTRIBUTE_GROUPS(ac97_dev);
+
+static int ac97_bus_match(struct device *dev, struct device_driver *drv)
+{
+       struct ac97_codec_device *adev = to_ac97_device(dev);
+       struct ac97_codec_driver *adrv = to_ac97_driver(drv);
+       const struct ac97_id *id = adrv->id_table;
+       int i = 0;
+
+       if (adev->vendor_id == 0x0 || adev->vendor_id == 0xffffffff)
+               return false;
+
+       do {
+               if (ac97_ids_match(id[i].id, adev->vendor_id, id[i].mask))
+                       return true;
+       } while (id[i++].id);
+
+       return false;
+}
+
+static int ac97_bus_probe(struct device *dev)
+{
+       struct ac97_codec_device *adev = to_ac97_device(dev);
+       struct ac97_codec_driver *adrv = to_ac97_driver(dev->driver);
+       int ret;
+
+       ret = ac97_get_enable_clk(adev);
+       if (ret)
+               return ret;
+
+       pm_runtime_get_noresume(dev);
+       pm_runtime_set_active(dev);
+       pm_runtime_enable(dev);
+
+       ret = adrv->probe(adev);
+       if (ret == 0)
+               return 0;
+
+       pm_runtime_disable(dev);
+       pm_runtime_set_suspended(dev);
+       pm_runtime_put_noidle(dev);
+       ac97_put_disable_clk(adev);
+
+       return ret;
+}
+
+static int ac97_bus_remove(struct device *dev)
+{
+       struct ac97_codec_device *adev = to_ac97_device(dev);
+       struct ac97_codec_driver *adrv = to_ac97_driver(dev->driver);
+       int ret;
+
+       ret = pm_runtime_get_sync(dev);
+       if (ret)
+               return ret;
+
+       ret = adrv->remove(adev);
+       pm_runtime_put_noidle(dev);
+       if (ret == 0)
+               ac97_put_disable_clk(adev);
+
+       return ret;
+}
+
+static struct bus_type ac97_bus_type = {
+       .name           = "ac97bus",
+       .dev_groups     = ac97_dev_groups,
+       .match          = ac97_bus_match,
+       .pm             = &ac97_pm,
+       .probe          = ac97_bus_probe,
+       .remove         = ac97_bus_remove,
+};
+
+static int __init ac97_bus_init(void)
+{
+       return bus_register(&ac97_bus_type);
+}
+subsys_initcall(ac97_bus_init);
+
+static void __exit ac97_bus_exit(void)
+{
+       bus_unregister(&ac97_bus_type);
+}
+module_exit(ac97_bus_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Robert Jarzmik <robert.jarzmik@free.fr>");
diff --git a/sound/ac97/codec.c b/sound/ac97/codec.c
new file mode 100644 (file)
index 0000000..a835f03
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ *  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_* */
+
diff --git a/sound/ac97/snd_ac97_compat.c b/sound/ac97/snd_ac97_compat.c
new file mode 100644 (file)
index 0000000..61544e0
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ *  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);
index 39c3969ac1c7fc7d6b977fc3d65cb995ba208aee..5950a9e218d962294b4e46f36e795e0af37b0250 100644 (file)
@@ -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;
index fbd5dad0c484006c1881156e2930d5020d589672..4bc244c40f80b45c223b8f186c7e694030734650 100644 (file)
 
 #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 = {
index 78187eb24f563fa2228d6c851b60980898387021..d5838402f667b39622c4ee01276df1eb75d0413b 100644 (file)
@@ -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.
index 1a66ec0366b237bdaeb00ada7c361b3a3d8c7adc..f07fd2e2870ace0aef7e277f80f006f81405e99e 100644 (file)
@@ -1,3 +1,5 @@
-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
index 08b1399d1da2b818b997b752555532ebdf45312e..9f521a55d610186ae78d433909edd26c8dc7035f 100644 (file)
@@ -20,7 +20,7 @@
 #include <linux/pm_runtime.h>
 
 #include <sound/soc.h>
-
+#include <drm/amd_asic_type.h>
 #include "acp.h"
 
 #define PLAYBACK_MIN_NUM_PERIODS    2
 #define MAX_BUFFER (PLAYBACK_MAX_PERIOD_SIZE * PLAYBACK_MAX_NUM_PERIODS)
 #define MIN_BUFFER MAX_BUFFER
 
+#define ST_PLAYBACK_MAX_PERIOD_SIZE 8192
+#define ST_CAPTURE_MAX_PERIOD_SIZE  ST_PLAYBACK_MAX_PERIOD_SIZE
+#define ST_MAX_BUFFER (ST_PLAYBACK_MAX_PERIOD_SIZE * PLAYBACK_MAX_NUM_PERIODS)
+#define ST_MIN_BUFFER ST_MAX_BUFFER
+
+#define DRV_NAME "acp_audio_dma"
+
 static const struct snd_pcm_hardware acp_pcm_hardware_playback = {
        .info = SNDRV_PCM_INFO_INTERLEAVED |
                SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP |
@@ -73,10 +80,42 @@ static const struct snd_pcm_hardware acp_pcm_hardware_capture = {
        .periods_max = CAPTURE_MAX_NUM_PERIODS,
 };
 
-struct audio_drv_data {
-       struct snd_pcm_substream *play_stream;
-       struct snd_pcm_substream *capture_stream;
-       void __iomem *acp_mmio;
+static const struct snd_pcm_hardware acp_st_pcm_hardware_playback = {
+       .info = SNDRV_PCM_INFO_INTERLEAVED |
+               SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP |
+               SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_BATCH |
+               SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME,
+       .formats = SNDRV_PCM_FMTBIT_S16_LE |
+               SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE,
+       .channels_min = 1,
+       .channels_max = 8,
+       .rates = SNDRV_PCM_RATE_8000_96000,
+       .rate_min = 8000,
+       .rate_max = 96000,
+       .buffer_bytes_max = ST_MAX_BUFFER,
+       .period_bytes_min = PLAYBACK_MIN_PERIOD_SIZE,
+       .period_bytes_max = ST_PLAYBACK_MAX_PERIOD_SIZE,
+       .periods_min = PLAYBACK_MIN_NUM_PERIODS,
+       .periods_max = PLAYBACK_MAX_NUM_PERIODS,
+};
+
+static const struct snd_pcm_hardware acp_st_pcm_hardware_capture = {
+       .info = SNDRV_PCM_INFO_INTERLEAVED |
+               SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP |
+               SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_BATCH |
+               SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME,
+       .formats = SNDRV_PCM_FMTBIT_S16_LE |
+               SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE,
+       .channels_min = 1,
+       .channels_max = 2,
+       .rates = SNDRV_PCM_RATE_8000_48000,
+       .rate_min = 8000,
+       .rate_max = 48000,
+       .buffer_bytes_max = ST_MAX_BUFFER,
+       .period_bytes_min = CAPTURE_MIN_PERIOD_SIZE,
+       .period_bytes_max = ST_CAPTURE_MAX_PERIOD_SIZE,
+       .periods_min = CAPTURE_MIN_NUM_PERIODS,
+       .periods_max = CAPTURE_MAX_NUM_PERIODS,
 };
 
 static u32 acp_reg_read(void __iomem *acp_mmio, u32 reg)
@@ -143,8 +182,8 @@ static void config_dma_descriptor_in_sram(void __iomem *acp_mmio,
  * system memory <-> ACP SRAM
  */
 static void set_acp_sysmem_dma_descriptors(void __iomem *acp_mmio,
-                                          u32 size, int direction,
-                                          u32 pte_offset)
+                                       u32 size, int direction,
+                                       u32 pte_offset, u32 asic_type)
 {
        u16 i;
        u16 dma_dscr_idx = PLAYBACK_START_DMA_DESCR_CH12;
@@ -154,24 +193,46 @@ static void set_acp_sysmem_dma_descriptors(void __iomem *acp_mmio,
                dmadscr[i].xfer_val = 0;
                if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
                        dma_dscr_idx = PLAYBACK_START_DMA_DESCR_CH12 + i;
-                       dmadscr[i].dest = ACP_SHARED_RAM_BANK_1_ADDRESS +
-                                       (size / 2) - (i * (size/2));
+                       dmadscr[i].dest = ACP_SHARED_RAM_BANK_1_ADDRESS
+                                       + (i * (size/2));
                        dmadscr[i].src = ACP_INTERNAL_APERTURE_WINDOW_0_ADDRESS
                                + (pte_offset * SZ_4K) + (i * (size/2));
-                       dmadscr[i].xfer_val |=
-                       (ACP_DMA_ATTRIBUTES_DAGB_ONION_TO_SHAREDMEM << 16) |
-                       (size / 2);
+                       switch (asic_type) {
+                       case CHIP_STONEY:
+                               dmadscr[i].xfer_val |=
+                               (ACP_DMA_ATTRIBUTES_DAGB_GARLIC_TO_SHAREDMEM  << 16) |
+                               (size / 2);
+                               break;
+                       default:
+                               dmadscr[i].xfer_val |=
+                               (ACP_DMA_ATTRIBUTES_DAGB_ONION_TO_SHAREDMEM  << 16) |
+                               (size / 2);
+                       }
                } else {
                        dma_dscr_idx = CAPTURE_START_DMA_DESCR_CH14 + i;
-                       dmadscr[i].src = ACP_SHARED_RAM_BANK_5_ADDRESS +
-                                       (i * (size/2));
-                       dmadscr[i].dest = ACP_INTERNAL_APERTURE_WINDOW_0_ADDRESS
-                                               + (pte_offset * SZ_4K) +
-                                               (i * (size/2));
-                       dmadscr[i].xfer_val |=
-                       BIT(22) |
-                       (ACP_DMA_ATTRIBUTES_SHAREDMEM_TO_DAGB_ONION << 16) |
-                       (size / 2);
+                       switch (asic_type) {
+                       case CHIP_STONEY:
+                               dmadscr[i].src = ACP_SHARED_RAM_BANK_3_ADDRESS +
+                               (i * (size/2));
+                               dmadscr[i].dest =
+                               ACP_INTERNAL_APERTURE_WINDOW_0_ADDRESS +
+                               (pte_offset * SZ_4K) + (i * (size/2));
+                               dmadscr[i].xfer_val |=
+                               BIT(22) |
+                               (ACP_DMA_ATTRIBUTES_SHARED_MEM_TO_DAGB_GARLIC << 16) |
+                               (size / 2);
+                               break;
+                       default:
+                               dmadscr[i].src = ACP_SHARED_RAM_BANK_5_ADDRESS +
+                               (i * (size/2));
+                               dmadscr[i].dest =
+                               ACP_INTERNAL_APERTURE_WINDOW_0_ADDRESS +
+                               (pte_offset * SZ_4K) + (i * (size/2));
+                               dmadscr[i].xfer_val |=
+                               BIT(22) |
+                               (ACP_DMA_ATTRIBUTES_SHAREDMEM_TO_DAGB_ONION << 16) |
+                               (size / 2);
+                       }
                }
                config_dma_descriptor_in_sram(acp_mmio, dma_dscr_idx,
                                                &dmadscr[i]);
@@ -192,7 +253,8 @@ static void set_acp_sysmem_dma_descriptors(void __iomem *acp_mmio,
  * ACP SRAM <-> I2S
  */
 static void set_acp_to_i2s_dma_descriptors(void __iomem *acp_mmio,
-                                          u32 size, int direction)
+                                       u32 size, int direction,
+                                       u32 asic_type)
 {
 
        u16 i;
@@ -213,8 +275,17 @@ static void set_acp_to_i2s_dma_descriptors(void __iomem *acp_mmio,
                        dma_dscr_idx = CAPTURE_START_DMA_DESCR_CH15 + i;
                        /* dmadscr[i].src is unused by hardware. */
                        dmadscr[i].src = 0;
-                       dmadscr[i].dest = ACP_SHARED_RAM_BANK_5_ADDRESS +
+                       switch (asic_type) {
+                       case CHIP_STONEY:
+                               dmadscr[i].dest =
+                                        ACP_SHARED_RAM_BANK_3_ADDRESS +
                                        (i * (size / 2));
+                               break;
+                       default:
+                               dmadscr[i].dest =
+                                        ACP_SHARED_RAM_BANK_5_ADDRESS +
+                                       (i * (size / 2));
+                       }
                        dmadscr[i].xfer_val |= BIT(22) |
                                        (FROM_ACP_I2S_1 << 16) | (size / 2);
                }
@@ -270,7 +341,8 @@ static void acp_pte_config(void __iomem *acp_mmio, struct page *pg,
 }
 
 static void config_acp_dma(void __iomem *acp_mmio,
-                          struct audio_substream_data *audio_config)
+                       struct audio_substream_data *audio_config,
+                       u32 asic_type)
 {
        u32 pte_offset;
 
@@ -284,11 +356,11 @@ static void config_acp_dma(void __iomem *acp_mmio,
 
        /* Configure System memory <-> ACP SRAM DMA descriptors */
        set_acp_sysmem_dma_descriptors(acp_mmio, audio_config->size,
-                                      audio_config->direction, pte_offset);
+                               audio_config->direction, pte_offset, asic_type);
 
        /* Configure ACP SRAM <-> I2S DMA descriptors */
        set_acp_to_i2s_dma_descriptors(acp_mmio, audio_config->size,
-                                       audio_config->direction);
+                               audio_config->direction, asic_type);
 }
 
 /* Start a given DMA channel transfer */
@@ -425,7 +497,7 @@ static void acp_set_sram_bank_state(void __iomem *acp_mmio, u16 bank,
 }
 
 /* Initialize and bring ACP hardware to default state. */
-static int acp_init(void __iomem *acp_mmio)
+static int acp_init(void __iomem *acp_mmio, u32 asic_type)
 {
        u16 bank;
        u32 val, count, sram_pte_offset;
@@ -499,10 +571,21 @@ static int acp_init(void __iomem *acp_mmio)
        /* When ACP_TILE_P1 is turned on, all SRAM banks get turned on.
        * Now, turn off all of them. This can't be done in 'poweron' of
        * ACP pm domain, as this requires ACP to be initialized.
+       * For Stoney, Memory gating is disabled,i.e SRAM Banks
+       * won't be turned off. The default state for SRAM banks is ON.
+       * Setting SRAM bank state code skipped for STONEY platform.
        */
-       for (bank = 1; bank < 48; bank++)
-               acp_set_sram_bank_state(acp_mmio, bank, false);
+       if (asic_type != CHIP_STONEY) {
+               for (bank = 1; bank < 48; bank++)
+                       acp_set_sram_bank_state(acp_mmio, bank, false);
+       }
 
+       /* Stoney supports 16bit resolution */
+       if (asic_type == CHIP_STONEY) {
+               val = acp_reg_read(acp_mmio, mmACP_I2S_16BIT_RESOLUTION_EN);
+               val |= 0x03;
+               acp_reg_write(val, acp_mmio, mmACP_I2S_16BIT_RESOLUTION_EN);
+       }
        return 0;
 }
 
@@ -572,9 +655,9 @@ static irqreturn_t dma_irq_handler(int irq, void *arg)
                valid_irq = true;
                if (acp_reg_read(acp_mmio, mmACP_DMA_CUR_DSCR_13) ==
                                PLAYBACK_START_DMA_DESCR_CH13)
-                       dscr_idx = PLAYBACK_START_DMA_DESCR_CH12;
-               else
                        dscr_idx = PLAYBACK_END_DMA_DESCR_CH12;
+               else
+                       dscr_idx = PLAYBACK_START_DMA_DESCR_CH12;
                config_acp_dma_channel(acp_mmio, SYSRAM_TO_ACP_CH_NUM, dscr_idx,
                                       1, 0);
                acp_dma_start(acp_mmio, SYSRAM_TO_ACP_CH_NUM, false);
@@ -626,10 +709,23 @@ static int acp_dma_open(struct snd_pcm_substream *substream)
        if (adata == NULL)
                return -ENOMEM;
 
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-               runtime->hw = acp_pcm_hardware_playback;
-       else
-               runtime->hw = acp_pcm_hardware_capture;
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               switch (intr_data->asic_type) {
+               case CHIP_STONEY:
+                       runtime->hw = acp_st_pcm_hardware_playback;
+                       break;
+               default:
+                       runtime->hw = acp_pcm_hardware_playback;
+               }
+       } else {
+               switch (intr_data->asic_type) {
+               case CHIP_STONEY:
+                       runtime->hw = acp_st_pcm_hardware_capture;
+                       break;
+               default:
+                       runtime->hw = acp_pcm_hardware_capture;
+               }
+       }
 
        ret = snd_pcm_hw_constraint_integer(runtime,
                                            SNDRV_PCM_HW_PARAM_PERIODS);
@@ -652,14 +748,22 @@ static int acp_dma_open(struct snd_pcm_substream *substream)
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
                intr_data->play_stream = substream;
-               for (bank = 1; bank <= 4; bank++)
-                       acp_set_sram_bank_state(intr_data->acp_mmio, bank,
-                                               true);
+               /* For Stoney, Memory gating is disabled,i.e SRAM Banks
+                * won't be turned off. The default state for SRAM banks is ON.
+                * Setting SRAM bank state code skipped for STONEY platform.
+                */
+               if (intr_data->asic_type != CHIP_STONEY) {
+                       for (bank = 1; bank <= 4; bank++)
+                               acp_set_sram_bank_state(intr_data->acp_mmio,
+                                                       bank, true);
+               }
        } else {
                intr_data->capture_stream = substream;
-               for (bank = 5; bank <= 8; bank++)
-                       acp_set_sram_bank_state(intr_data->acp_mmio, bank,
-                                               true);
+               if (intr_data->asic_type != CHIP_STONEY) {
+                       for (bank = 5; bank <= 8; bank++)
+                               acp_set_sram_bank_state(intr_data->acp_mmio,
+                                                       bank, true);
+               }
        }
 
        return 0;
@@ -673,6 +777,8 @@ static int acp_dma_hw_params(struct snd_pcm_substream *substream,
        struct page *pg;
        struct snd_pcm_runtime *runtime;
        struct audio_substream_data *rtd;
+       struct snd_soc_pcm_runtime *prtd = substream->private_data;
+       struct audio_drv_data *adata = dev_get_drvdata(prtd->platform->dev);
 
        runtime = substream->runtime;
        rtd = runtime->private_data;
@@ -700,7 +806,7 @@ static int acp_dma_hw_params(struct snd_pcm_substream *substream,
                rtd->num_of_pages = PAGE_ALIGN(size) >> PAGE_SHIFT;
                rtd->direction = substream->stream;
 
-               config_acp_dma(rtd->acp_mmio, rtd);
+               config_acp_dma(rtd->acp_mmio, rtd, adata->asic_type);
                status = 0;
        } else {
                status = -ENOMEM;
@@ -713,40 +819,48 @@ static int acp_dma_hw_free(struct snd_pcm_substream *substream)
        return snd_pcm_lib_free_pages(substream);
 }
 
+static u64 acp_get_byte_count(void __iomem *acp_mmio, int stream)
+{
+       union acp_dma_count playback_dma_count;
+       union acp_dma_count capture_dma_count;
+       u64 bytescount = 0;
+
+       if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               playback_dma_count.bcount.high = acp_reg_read(acp_mmio,
+                                       mmACP_I2S_TRANSMIT_BYTE_CNT_HIGH);
+               playback_dma_count.bcount.low  = acp_reg_read(acp_mmio,
+                                       mmACP_I2S_TRANSMIT_BYTE_CNT_LOW);
+               bytescount = playback_dma_count.bytescount;
+       } else {
+               capture_dma_count.bcount.high = acp_reg_read(acp_mmio,
+                                       mmACP_I2S_RECEIVED_BYTE_CNT_HIGH);
+               capture_dma_count.bcount.low  = acp_reg_read(acp_mmio,
+                                       mmACP_I2S_RECEIVED_BYTE_CNT_LOW);
+               bytescount = capture_dma_count.bytescount;
+       }
+       return bytescount;
+}
+
 static snd_pcm_uframes_t acp_dma_pointer(struct snd_pcm_substream *substream)
 {
-       u16 dscr;
-       u32 mul, dma_config, period_bytes;
+       u32 buffersize;
        u32 pos = 0;
+       u64 bytescount = 0;
 
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct audio_substream_data *rtd = runtime->private_data;
 
-       period_bytes = frames_to_bytes(runtime, runtime->period_size);
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               dscr = acp_reg_read(rtd->acp_mmio, mmACP_DMA_CUR_DSCR_13);
+       buffersize = frames_to_bytes(runtime, runtime->buffer_size);
+       bytescount = acp_get_byte_count(rtd->acp_mmio, substream->stream);
 
-               if (dscr == PLAYBACK_START_DMA_DESCR_CH13)
-                       mul = 0;
-               else
-                       mul = 1;
-               pos =  (mul * period_bytes);
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               if (bytescount > rtd->renderbytescount)
+                       bytescount = bytescount - rtd->renderbytescount;
        } else {
-               dma_config = acp_reg_read(rtd->acp_mmio, mmACP_DMA_CNTL_14);
-               if (dma_config != 0) {
-                       dscr = acp_reg_read(rtd->acp_mmio,
-                                               mmACP_DMA_CUR_DSCR_14);
-                       if (dscr == CAPTURE_START_DMA_DESCR_CH14)
-                               mul = 1;
-                       else
-                               mul = 2;
-                       pos = (mul * period_bytes);
-               }
-
-               if (pos >= (2 * period_bytes))
-                       pos = 0;
-
+               if (bytescount > rtd->capturebytescount)
+                       bytescount = bytescount - rtd->capturebytescount;
        }
+       pos = do_div(bytescount, buffersize);
        return bytes_to_frames(runtime, pos);
 }
 
@@ -768,23 +882,6 @@ static int acp_dma_prepare(struct snd_pcm_substream *substream)
                config_acp_dma_channel(rtd->acp_mmio, ACP_TO_I2S_DMA_CH_NUM,
                                        PLAYBACK_START_DMA_DESCR_CH13,
                                        NUM_DSCRS_PER_CHANNEL, 0);
-               /* Fill ACP SRAM (2 periods) with zeros from System RAM
-                * which is zero-ed in hw_params
-               */
-               acp_dma_start(rtd->acp_mmio, SYSRAM_TO_ACP_CH_NUM, false);
-
-               /* ACP SRAM (2 periods of buffer size) is intially filled with
-                * zeros. Before rendering starts, 2nd half of SRAM will be
-                * filled with valid audio data DMA'ed from first half of system
-                * RAM and 1st half of SRAM will be filled with Zeros. This is
-                * the initial scenario when redering starts from SRAM. Later
-                * on, 2nd half of system memory will be DMA'ed to 1st half of
-                * SRAM, 1st half of system memory will be DMA'ed to 2nd half of
-                * SRAM in ping-pong way till rendering stops.
-               */
-               config_acp_dma_channel(rtd->acp_mmio, SYSRAM_TO_ACP_CH_NUM,
-                                       PLAYBACK_START_DMA_DESCR_CH12,
-                                       1, 0);
        } else {
                config_acp_dma_channel(rtd->acp_mmio, ACP_TO_SYSRAM_CH_NUM,
                                        CAPTURE_START_DMA_DESCR_CH14,
@@ -799,7 +896,8 @@ static int acp_dma_prepare(struct snd_pcm_substream *substream)
 static int acp_dma_trigger(struct snd_pcm_substream *substream, int cmd)
 {
        int ret;
-       u32 loops = 1000;
+       u32 loops = 4000;
+       u64 bytescount = 0;
 
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct snd_soc_pcm_runtime *prtd = substream->private_data;
@@ -811,7 +909,11 @@ static int acp_dma_trigger(struct snd_pcm_substream *substream, int cmd)
        case SNDRV_PCM_TRIGGER_START:
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
        case SNDRV_PCM_TRIGGER_RESUME:
+               bytescount = acp_get_byte_count(rtd->acp_mmio,
+                                               substream->stream);
                if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+                       if (rtd->renderbytescount == 0)
+                               rtd->renderbytescount = bytescount;
                        acp_dma_start(rtd->acp_mmio,
                                                SYSRAM_TO_ACP_CH_NUM, false);
                        while (acp_reg_read(rtd->acp_mmio, mmACP_DMA_CH_STS) &
@@ -828,6 +930,8 @@ static int acp_dma_trigger(struct snd_pcm_substream *substream, int cmd)
                                        ACP_TO_I2S_DMA_CH_NUM, true);
 
                } else {
+                       if (rtd->capturebytescount == 0)
+                               rtd->capturebytescount = bytescount;
                        acp_dma_start(rtd->acp_mmio,
                                            I2S_TO_ACP_DMA_CH_NUM, true);
                }
@@ -841,12 +945,15 @@ static int acp_dma_trigger(struct snd_pcm_substream *substream, int cmd)
                 * channels will stopped automatically after its transfer
                 * completes : SYSRAM_TO_ACP_CH_NUM / ACP_TO_SYSRAM_CH_NUM
                 */
-               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
                        ret = acp_dma_stop(rtd->acp_mmio,
                                        ACP_TO_I2S_DMA_CH_NUM);
-               else
+                       rtd->renderbytescount = 0;
+               } else {
                        ret = acp_dma_stop(rtd->acp_mmio,
                                        I2S_TO_ACP_DMA_CH_NUM);
+                       rtd->capturebytescount = 0;
+               }
                break;
        default:
                ret = -EINVAL;
@@ -857,10 +964,27 @@ static int acp_dma_trigger(struct snd_pcm_substream *substream, int cmd)
 
 static int acp_dma_new(struct snd_soc_pcm_runtime *rtd)
 {
-       return snd_pcm_lib_preallocate_pages_for_all(rtd->pcm,
+       int ret;
+       struct audio_drv_data *adata = dev_get_drvdata(rtd->platform->dev);
+
+       switch (adata->asic_type) {
+       case CHIP_STONEY:
+               ret = snd_pcm_lib_preallocate_pages_for_all(rtd->pcm,
+                                                       SNDRV_DMA_TYPE_DEV,
+                                                       NULL, ST_MIN_BUFFER,
+                                                       ST_MAX_BUFFER);
+               break;
+       default:
+               ret = snd_pcm_lib_preallocate_pages_for_all(rtd->pcm,
                                                        SNDRV_DMA_TYPE_DEV,
                                                        NULL, MIN_BUFFER,
                                                        MAX_BUFFER);
+               break;
+       }
+       if (ret < 0)
+               dev_err(rtd->platform->dev,
+                               "buffer preallocation failer error:%d\n", ret);
+       return ret;
 }
 
 static int acp_dma_close(struct snd_pcm_substream *substream)
@@ -875,14 +999,23 @@ static int acp_dma_close(struct snd_pcm_substream *substream)
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
                adata->play_stream = NULL;
-               for (bank = 1; bank <= 4; bank++)
-                       acp_set_sram_bank_state(adata->acp_mmio, bank,
-                                               false);
-       } else {
+               /* For Stoney, Memory gating is disabled,i.e SRAM Banks
+                * won't be turned off. The default state for SRAM banks is ON.
+                * Setting SRAM bank state code skipped for STONEY platform.
+                * added condition checks for Carrizo platform only
+                */
+               if (adata->asic_type != CHIP_STONEY) {
+                       for (bank = 1; bank <= 4; bank++)
+                               acp_set_sram_bank_state(adata->acp_mmio, bank,
+                               false);
+               }
+       } else  {
                adata->capture_stream = NULL;
-               for (bank = 5; bank <= 8; bank++)
-                       acp_set_sram_bank_state(adata->acp_mmio, bank,
-                                               false);
+               if (adata->asic_type != CHIP_STONEY) {
+                       for (bank = 5; bank <= 8; bank++)
+                               acp_set_sram_bank_state(adata->acp_mmio, bank,
+                                                    false);
+               }
        }
 
        /* Disable ACP irq, when the current stream is being closed and
@@ -916,6 +1049,7 @@ static int acp_audio_probe(struct platform_device *pdev)
        int status;
        struct audio_drv_data *audio_drv_data;
        struct resource *res;
+       const u32 *pdata = pdev->dev.platform_data;
 
        audio_drv_data = devm_kzalloc(&pdev->dev, sizeof(struct audio_drv_data),
                                        GFP_KERNEL);
@@ -932,6 +1066,7 @@ static int acp_audio_probe(struct platform_device *pdev)
 
        audio_drv_data->play_stream = NULL;
        audio_drv_data->capture_stream = NULL;
+       audio_drv_data->asic_type =  *pdata;
 
        res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
        if (!res) {
@@ -949,7 +1084,7 @@ static int acp_audio_probe(struct platform_device *pdev)
        dev_set_drvdata(&pdev->dev, audio_drv_data);
 
        /* Initialize the ACP */
-       acp_init(audio_drv_data->acp_mmio);
+       acp_init(audio_drv_data->acp_mmio, audio_drv_data->asic_type);
 
        status = snd_soc_register_platform(&pdev->dev, &acp_asoc_platform);
        if (status != 0) {
@@ -980,21 +1115,31 @@ static int acp_pcm_resume(struct device *dev)
        u16 bank;
        struct audio_drv_data *adata = dev_get_drvdata(dev);
 
-       acp_init(adata->acp_mmio);
+       acp_init(adata->acp_mmio, adata->asic_type);
 
        if (adata->play_stream && adata->play_stream->runtime) {
-               for (bank = 1; bank <= 4; bank++)
-                       acp_set_sram_bank_state(adata->acp_mmio, bank,
+               /* For Stoney, Memory gating is disabled,i.e SRAM Banks
+                * won't be turned off. The default state for SRAM banks is ON.
+                * Setting SRAM bank state code skipped for STONEY platform.
+                */
+               if (adata->asic_type != CHIP_STONEY) {
+                       for (bank = 1; bank <= 4; bank++)
+                               acp_set_sram_bank_state(adata->acp_mmio, bank,
                                                true);
+               }
                config_acp_dma(adata->acp_mmio,
-                               adata->play_stream->runtime->private_data);
+                       adata->play_stream->runtime->private_data,
+                       adata->asic_type);
        }
        if (adata->capture_stream && adata->capture_stream->runtime) {
-               for (bank = 5; bank <= 8; bank++)
-                       acp_set_sram_bank_state(adata->acp_mmio, bank,
+               if (adata->asic_type != CHIP_STONEY) {
+                       for (bank = 5; bank <= 8; bank++)
+                               acp_set_sram_bank_state(adata->acp_mmio, bank,
                                                true);
+               }
                config_acp_dma(adata->acp_mmio,
-                               adata->capture_stream->runtime->private_data);
+                       adata->capture_stream->runtime->private_data,
+                       adata->asic_type);
        }
        acp_reg_write(1, adata->acp_mmio, mmACP_EXTERNAL_INTR_ENB);
        return 0;
@@ -1013,7 +1158,7 @@ static int acp_pcm_runtime_resume(struct device *dev)
 {
        struct audio_drv_data *adata = dev_get_drvdata(dev);
 
-       acp_init(adata->acp_mmio);
+       acp_init(adata->acp_mmio, adata->asic_type);
        acp_reg_write(1, adata->acp_mmio, mmACP_EXTERNAL_INTR_ENB);
        return 0;
 }
@@ -1028,14 +1173,15 @@ static struct platform_driver acp_dma_driver = {
        .probe = acp_audio_probe,
        .remove = acp_audio_remove,
        .driver = {
-               .name = "acp_audio_dma",
+               .name = DRV_NAME,
                .pm = &acp_pm_ops,
        },
 };
 
 module_platform_driver(acp_dma_driver);
 
+MODULE_AUTHOR("Vijendar.Mukunda@amd.com");
 MODULE_AUTHOR("Maruthi.Bayyavarapu@amd.com");
 MODULE_DESCRIPTION("AMD ACP PCM Driver");
 MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:acp-dma-audio");
+MODULE_ALIAS("platform:"DRV_NAME);
diff --git a/sound/soc/amd/acp-rt5645.c b/sound/soc/amd/acp-rt5645.c
new file mode 100644 (file)
index 0000000..941aed6
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ * 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");
index 9d338216c5ae8f9b16979beffa74230f33b075cd..ecb458935d1e82607f907c9105ccaac20411f8ce 100644 (file)
@@ -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,
index a1149f6a8450e71031c5bb3dd21c82a468c11700..b3375e19598a8372dbedbb4e012cb343d5c0fbdb 100644 (file)
@@ -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");
index 1822e3b3de805986001f8a037fb0b91f1f83d8c0..dfdf6d8c9687f72d4bfc0ff77d9c0b132687e56d 100644 (file)
@@ -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
index e09fc8f037f10c5f04d62369c89852ab3b9273cc..94c0209977d0bfd2a9a63bc0a4858d26a5a5a3a5 100644 (file)
@@ -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;
index 72486bf072f2854de417804afab7002158f8b333..4f0481d3c7a7117894c209d217d403e1946d5393 100644 (file)
@@ -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;
index 858a24fc28e80065052d4bff98831680197c5927..6ed1e1f9ce516cb4867f51a0edb1e83e5ddf34a7 100644 (file)
@@ -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;
index 49401a8aae64a972ceaf4e1a4d79717a2e9b6603..77f512767273f4e0813f77bdce632e46b1fd83fb 100644 (file)
@@ -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;
index 4b64bb46eb21bb426d153e3dc119fc3396e16fbf..2d211dbe742255d5b777924f92c20a867e424f35 100644 (file)
@@ -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;
index f49bf02e5ec2426f8462fc195746bd268a53cde6..803818aabee98f03ffc6bd877830aa73f463392e 100644 (file)
 
 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,
 };