]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge remote-tracking branches 'asoc/topic/rcar', 'asoc/topic/reg-default', 'asoc...
authorMark Brown <broonie@kernel.org>
Sun, 30 Aug 2015 14:55:54 +0000 (15:55 +0100)
committerMark Brown <broonie@kernel.org>
Sun, 30 Aug 2015 14:55:54 +0000 (15:55 +0100)
46 files changed:
Documentation/devicetree/bindings/sound/renesas,rsnd.txt
Documentation/devicetree/bindings/sound/renesas,rsrc-card.txt
drivers/base/regmap/internal.h
drivers/base/regmap/regmap.c
drivers/gpu/drm/i2c/adv7511.c
drivers/input/misc/drv260x.c
drivers/input/misc/drv2665.c
drivers/input/misc/drv2667.c
drivers/mfd/arizona-core.c
drivers/mfd/twl6040.c
drivers/mfd/wm5102-tables.c
drivers/mfd/wm5110-tables.c
drivers/mfd/wm8994-core.c
drivers/mfd/wm8997-tables.c
include/linux/regmap.h
include/sound/rcar_snd.h
sound/soc/codecs/arizona.c
sound/soc/codecs/cs35l32.c
sound/soc/codecs/cs42l52.c
sound/soc/codecs/da7210.c
sound/soc/codecs/rl6231.c
sound/soc/codecs/rl6231.h
sound/soc/codecs/rt286.c
sound/soc/codecs/rt5640.c
sound/soc/codecs/rt5645.c
sound/soc/codecs/rt5651.c
sound/soc/codecs/rt5670.c
sound/soc/codecs/rt5677.c
sound/soc/codecs/tlv320aic3x.c
sound/soc/codecs/wm2200.c
sound/soc/codecs/wm5100.c
sound/soc/codecs/wm8962.c
sound/soc/codecs/wm8993.c
sound/soc/rockchip/rockchip_max98090.c
sound/soc/rockchip/rockchip_rt5645.c
sound/soc/sh/rcar/Makefile
sound/soc/sh/rcar/core.c
sound/soc/sh/rcar/ctu.c [new file with mode: 0644]
sound/soc/sh/rcar/dma.c
sound/soc/sh/rcar/dvc.c
sound/soc/sh/rcar/gen.c
sound/soc/sh/rcar/mix.c [new file with mode: 0644]
sound/soc/sh/rcar/rsnd.h
sound/soc/sh/rcar/rsrc-card.c
sound/soc/sh/rcar/src.c
sound/soc/sh/rcar/ssi.c

index b6b3a786855f275b3463d8280db01af8262f6df3..1173395b5e5c16c070885b06ae06100eb0aa7ff2 100644 (file)
@@ -18,6 +18,12 @@ Required properties:
 - rcar_sound,src               : Should contain SRC feature.
                                  The number of SRC subnode should be same as HW.
                                  see below for detail.
+- rcar_sound,ctu               : Should contain CTU feature.
+                                 The number of CTU subnode should be same as HW.
+                                 see below for detail.
+- rcar_sound,mix               : Should contain MIX feature.
+                                 The number of MIX subnode should be same as HW.
+                                 see below for detail.
 - rcar_sound,dvc               : Should contain DVC feature.
                                  The number of DVC subnode should be same as HW.
                                  see below for detail.
@@ -90,6 +96,22 @@ rcar_sound: sound@ec500000 {
                };
        };
 
+       rcar_sound,mix {
+               mix0: mix@0 { };
+               mix1: mix@1 { };
+       };
+
+       rcar_sound,ctu {
+               ctu00: ctu@0 { };
+               ctu01: ctu@1 { };
+               ctu02: ctu@2 { };
+               ctu03: ctu@3 { };
+               ctu10: ctu@4 { };
+               ctu11: ctu@5 { };
+               ctu12: ctu@6 { };
+               ctu13: ctu@7 { };
+       };
+
        rcar_sound,src {
                src0: src@0 {
                        interrupts = <0 352 IRQ_TYPE_LEVEL_HIGH>;
index c64155027288e20105f4741bc66de02951b7c1a3..962748a8d9194dee2101c681a80f18ed06825422 100644 (file)
@@ -6,6 +6,7 @@ Required properties:
 
 - compatible                           : "renesas,rsrc-card,<board>"
                                          Examples with soctypes are:
+                                           - "renesas,rsrc-card"
                                            - "renesas,rsrc-card,lager"
                                            - "renesas,rsrc-card,koelsch"
 Optional properties:
@@ -29,6 +30,12 @@ Optional subnode properties:
 - frame-inversion                      : bool property. Add this if the
                                          dai-link uses frame clock inversion.
 - convert-rate                         : platform specified sampling rate convert
+- audio-prefix                         : see audio-routing
+- audio-routing                                : A list of the connections between audio components.
+                                         Each entry is a pair of strings, the first being the connection's sink,
+                                         the second being the connection's source. Valid names for sources.
+                                         use audio-prefix if some components is using same sink/sources naming.
+                                         it can be used if compatible was "renesas,rsrc-card";
 
 Required CPU/CODEC subnodes properties:
 
index b2b2849fc6d3b34d1294a02ef009a10af86d49de..873ddf91c9d3ec742ceb1c3a9959ac322adc16db 100644 (file)
@@ -136,7 +136,7 @@ struct regmap {
        /* if set, the HW registers are known to match map->reg_defaults */
        bool no_sync_defaults;
 
-       struct reg_default *patch;
+       struct reg_sequence *patch;
        int patch_regs;
 
        /* if set, converts bulk rw to single rw */
index 7111d04f26218be0529f4702cb1b361ae07a0b00..0a849eeaf952aefdca5fc7793fe339a5de4b96e2 100644 (file)
@@ -34,7 +34,7 @@
 
 static int _regmap_update_bits(struct regmap *map, unsigned int reg,
                               unsigned int mask, unsigned int val,
-                              bool *change);
+                              bool *change, bool force_write);
 
 static int _regmap_bus_reg_read(void *context, unsigned int reg,
                                unsigned int *val);
@@ -1178,7 +1178,7 @@ static int _regmap_select_page(struct regmap *map, unsigned int *reg,
                ret = _regmap_update_bits(map, range->selector_reg,
                                          range->selector_mask,
                                          win_page << range->selector_shift,
-                                         &page_chg);
+                                         &page_chg, false);
 
                map->work_buf = orig_work_buf;
 
@@ -1624,6 +1624,18 @@ int regmap_fields_write(struct regmap_field *field, unsigned int id,
 }
 EXPORT_SYMBOL_GPL(regmap_fields_write);
 
+int regmap_fields_force_write(struct regmap_field *field, unsigned int id,
+                       unsigned int val)
+{
+       if (id >= field->id_size)
+               return -EINVAL;
+
+       return regmap_write_bits(field->regmap,
+                                 field->reg + (field->id_offset * id),
+                                 field->mask, val << field->shift);
+}
+EXPORT_SYMBOL_GPL(regmap_fields_force_write);
+
 /**
  * regmap_fields_update_bits():        Perform a read/modify/write cycle
  *                              on the register field
@@ -1743,7 +1755,7 @@ EXPORT_SYMBOL_GPL(regmap_bulk_write);
  * relative. The page register has been written if that was neccessary.
  */
 static int _regmap_raw_multi_reg_write(struct regmap *map,
-                                      const struct reg_default *regs,
+                                      const struct reg_sequence *regs,
                                       size_t num_regs)
 {
        int ret;
@@ -1800,12 +1812,12 @@ static unsigned int _regmap_register_page(struct regmap *map,
 }
 
 static int _regmap_range_multi_paged_reg_write(struct regmap *map,
-                                              struct reg_default *regs,
+                                              struct reg_sequence *regs,
                                               size_t num_regs)
 {
        int ret;
        int i, n;
-       struct reg_default *base;
+       struct reg_sequence *base;
        unsigned int this_page = 0;
        /*
         * the set of registers are not neccessarily in order, but
@@ -1843,7 +1855,7 @@ static int _regmap_range_multi_paged_reg_write(struct regmap *map,
 }
 
 static int _regmap_multi_reg_write(struct regmap *map,
-                                  const struct reg_default *regs,
+                                  const struct reg_sequence *regs,
                                   size_t num_regs)
 {
        int i;
@@ -1895,8 +1907,8 @@ static int _regmap_multi_reg_write(struct regmap *map,
                struct regmap_range_node *range;
                range = _regmap_range_lookup(map, reg);
                if (range) {
-                       size_t len = sizeof(struct reg_default)*num_regs;
-                       struct reg_default *base = kmemdup(regs, len,
+                       size_t len = sizeof(struct reg_sequence)*num_regs;
+                       struct reg_sequence *base = kmemdup(regs, len,
                                                           GFP_KERNEL);
                        if (!base)
                                return -ENOMEM;
@@ -1929,7 +1941,7 @@ static int _regmap_multi_reg_write(struct regmap *map,
  * A value of zero will be returned on success, a negative errno will be
  * returned in error cases.
  */
-int regmap_multi_reg_write(struct regmap *map, const struct reg_default *regs,
+int regmap_multi_reg_write(struct regmap *map, const struct reg_sequence *regs,
                           int num_regs)
 {
        int ret;
@@ -1962,7 +1974,7 @@ EXPORT_SYMBOL_GPL(regmap_multi_reg_write);
  * be returned in error cases.
  */
 int regmap_multi_reg_write_bypassed(struct regmap *map,
-                                   const struct reg_default *regs,
+                                   const struct reg_sequence *regs,
                                    int num_regs)
 {
        int ret;
@@ -2327,7 +2339,7 @@ EXPORT_SYMBOL_GPL(regmap_bulk_read);
 
 static int _regmap_update_bits(struct regmap *map, unsigned int reg,
                               unsigned int mask, unsigned int val,
-                              bool *change)
+                              bool *change, bool force_write)
 {
        int ret;
        unsigned int tmp, orig;
@@ -2339,7 +2351,7 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg,
        tmp = orig & ~mask;
        tmp |= val & mask;
 
-       if (tmp != orig) {
+       if (force_write || (tmp != orig)) {
                ret = _regmap_write(map, reg, tmp);
                if (change)
                        *change = true;
@@ -2367,13 +2379,36 @@ int regmap_update_bits(struct regmap *map, unsigned int reg,
        int ret;
 
        map->lock(map->lock_arg);
-       ret = _regmap_update_bits(map, reg, mask, val, NULL);
+       ret = _regmap_update_bits(map, reg, mask, val, NULL, false);
        map->unlock(map->lock_arg);
 
        return ret;
 }
 EXPORT_SYMBOL_GPL(regmap_update_bits);
 
+/**
+ * regmap_write_bits: Perform a read/modify/write cycle on the register map
+ *
+ * @map: Register map to update
+ * @reg: Register to update
+ * @mask: Bitmask to change
+ * @val: New value for bitmask
+ *
+ * Returns zero for success, a negative number on error.
+ */
+int regmap_write_bits(struct regmap *map, unsigned int reg,
+                     unsigned int mask, unsigned int val)
+{
+       int ret;
+
+       map->lock(map->lock_arg);
+       ret = _regmap_update_bits(map, reg, mask, val, NULL, true);
+       map->unlock(map->lock_arg);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(regmap_write_bits);
+
 /**
  * regmap_update_bits_async: Perform a read/modify/write cycle on the register
  *                           map asynchronously
@@ -2398,7 +2433,7 @@ int regmap_update_bits_async(struct regmap *map, unsigned int reg,
 
        map->async = true;
 
-       ret = _regmap_update_bits(map, reg, mask, val, NULL);
+       ret = _regmap_update_bits(map, reg, mask, val, NULL, false);
 
        map->async = false;
 
@@ -2427,7 +2462,7 @@ int regmap_update_bits_check(struct regmap *map, unsigned int reg,
        int ret;
 
        map->lock(map->lock_arg);
-       ret = _regmap_update_bits(map, reg, mask, val, change);
+       ret = _regmap_update_bits(map, reg, mask, val, change, false);
        map->unlock(map->lock_arg);
        return ret;
 }
@@ -2460,7 +2495,7 @@ int regmap_update_bits_check_async(struct regmap *map, unsigned int reg,
 
        map->async = true;
 
-       ret = _regmap_update_bits(map, reg, mask, val, change);
+       ret = _regmap_update_bits(map, reg, mask, val, change, false);
 
        map->async = false;
 
@@ -2552,10 +2587,10 @@ EXPORT_SYMBOL_GPL(regmap_async_complete);
  * The caller must ensure that this function cannot be called
  * concurrently with either itself or regcache_sync().
  */
-int regmap_register_patch(struct regmap *map, const struct reg_default *regs,
+int regmap_register_patch(struct regmap *map, const struct reg_sequence *regs,
                          int num_regs)
 {
-       struct reg_default *p;
+       struct reg_sequence *p;
        int ret;
        bool bypass;
 
@@ -2564,7 +2599,7 @@ int regmap_register_patch(struct regmap *map, const struct reg_default *regs,
                return 0;
 
        p = krealloc(map->patch,
-                    sizeof(struct reg_default) * (map->patch_regs + num_regs),
+                    sizeof(struct reg_sequence) * (map->patch_regs + num_regs),
                     GFP_KERNEL);
        if (p) {
                memcpy(p + map->patch_regs, regs, num_regs * sizeof(*regs));
index 2aaa3c88999e32c0f951312b48aedded13f837e0..00416f23b5cb5fef4bbdf9ade8d2a794737d6789 100644 (file)
@@ -54,7 +54,7 @@ static struct adv7511 *encoder_to_adv7511(struct drm_encoder *encoder)
 }
 
 /* ADI recommended values for proper operation. */
-static const struct reg_default adv7511_fixed_registers[] = {
+static const struct reg_sequence adv7511_fixed_registers[] = {
        { 0x98, 0x03 },
        { 0x9a, 0xe0 },
        { 0x9c, 0x30 },
index e5d60ecd29a4d6adc2ae63cdfe69fea935edeb58..f5c9cf2f4073adf8671aaae0287dcf83e64d8c52 100644 (file)
@@ -313,14 +313,14 @@ static void drv260x_close(struct input_dev *input)
        gpiod_set_value(haptics->enable_gpio, 0);
 }
 
-static const struct reg_default drv260x_lra_cal_regs[] = {
+static const struct reg_sequence drv260x_lra_cal_regs[] = {
        { DRV260X_MODE, DRV260X_AUTO_CAL },
        { DRV260X_CTRL3, DRV260X_NG_THRESH_2 },
        { DRV260X_FEEDBACK_CTRL, DRV260X_FB_REG_LRA_MODE |
                DRV260X_BRAKE_FACTOR_4X | DRV260X_LOOP_GAIN_HIGH },
 };
 
-static const struct reg_default drv260x_lra_init_regs[] = {
+static const struct reg_sequence drv260x_lra_init_regs[] = {
        { DRV260X_MODE, DRV260X_RT_PLAYBACK },
        { DRV260X_A_TO_V_CTRL, DRV260X_AUDIO_HAPTICS_PEAK_20MS |
                DRV260X_AUDIO_HAPTICS_FILTER_125HZ },
@@ -337,7 +337,7 @@ static const struct reg_default drv260x_lra_init_regs[] = {
        { DRV260X_CTRL4, DRV260X_AUTOCAL_TIME_500MS },
 };
 
-static const struct reg_default drv260x_erm_cal_regs[] = {
+static const struct reg_sequence drv260x_erm_cal_regs[] = {
        { DRV260X_MODE, DRV260X_AUTO_CAL },
        { DRV260X_A_TO_V_MIN_INPUT, DRV260X_AUDIO_HAPTICS_MIN_IN_VOLT },
        { DRV260X_A_TO_V_MAX_INPUT, DRV260X_AUDIO_HAPTICS_MAX_IN_VOLT },
index 0afaa33de07d2d46e59e3a44d204ec4322e035ba..924456e3ca75d71af762287f28f8b15d71024692 100644 (file)
@@ -132,7 +132,7 @@ static void drv2665_close(struct input_dev *input)
                        "Failed to enter standby mode: %d\n", error);
 }
 
-static const struct reg_default drv2665_init_regs[] = {
+static const struct reg_sequence drv2665_init_regs[] = {
        { DRV2665_CTRL_2, 0 | DRV2665_10_MS_IDLE_TOUT },
        { DRV2665_CTRL_1, DRV2665_25_VPP_GAIN },
 };
index fc0fddf0896a772f911f36decd1fdbadaa727f7d..047136aa646f28c9b5f52dd3d988a0d5e2b9aeef 100644 (file)
@@ -262,14 +262,14 @@ static void drv2667_close(struct input_dev *input)
                        "Failed to enter standby mode: %d\n", error);
 }
 
-static const struct reg_default drv2667_init_regs[] = {
+static const struct reg_sequence drv2667_init_regs[] = {
        { DRV2667_CTRL_2, 0 },
        { DRV2667_CTRL_1, DRV2667_25_VPP_GAIN },
        { DRV2667_WV_SEQ_0, 1 },
        { DRV2667_WV_SEQ_1, 0 }
 };
 
-static const struct reg_default drv2667_page1_init[] = {
+static const struct reg_sequence drv2667_page1_init[] = {
        { DRV2667_RAM_HDR_SZ, 0x05 },
        { DRV2667_RAM_START_HI, 0x80 },
        { DRV2667_RAM_START_LO, 0x06 },
index a72ddb2950784cf044fbfb5156ebd68866bbea48..0ce20ce170c41793d88febd54302d261b92df9db 100644 (file)
@@ -392,7 +392,7 @@ err:
  * Register patch to some of the CODECs internal write sequences
  * to ensure a clean exit from the low power sleep state.
  */
-static const struct reg_default wm5110_sleep_patch[] = {
+static const struct reg_sequence wm5110_sleep_patch[] = {
        { 0x337A, 0xC100 },
        { 0x337B, 0x0041 },
        { 0x3300, 0xA210 },
index c5265c1262c50c3496f9142c07704d78d799a1b0..583dc33432f31ed056aa53e4e37582fefc4f7e71 100644 (file)
@@ -86,7 +86,7 @@ static const struct reg_default twl6040_defaults[] = {
        { 0x2E, 0x00 }, /* REG_STATUS   (ro) */
 };
 
-static struct reg_default twl6040_patch[] = {
+static struct reg_sequence twl6040_patch[] = {
        /*
         * Select I2C bus access to dual access registers
         * Interrupt register is cleared on read
index aeae6ec123b3ad76c8d7eec6f4ba326c1419907e..423fb3730dc714f17accd85d9aa9eda9b29b8ebf 100644 (file)
@@ -21,7 +21,7 @@
 #define WM5102_NUM_AOD_ISR 2
 #define WM5102_NUM_ISR 5
 
-static const struct reg_default wm5102_reva_patch[] = {
+static const struct reg_sequence wm5102_reva_patch[] = {
        { 0x80, 0x0003 },
        { 0x221, 0x0090 },
        { 0x211, 0x0014 },
@@ -57,7 +57,7 @@ static const struct reg_default wm5102_reva_patch[] = {
        { 0x80, 0x0000 },
 };
 
-static const struct reg_default wm5102_revb_patch[] = {
+static const struct reg_sequence wm5102_revb_patch[] = {
        { 0x19, 0x0001 },
        { 0x80, 0x0003 },
        { 0x081, 0xE022 },
@@ -80,7 +80,7 @@ static const struct reg_default wm5102_revb_patch[] = {
 /* We use a function so we can use ARRAY_SIZE() */
 int wm5102_patch(struct arizona *arizona)
 {
-       const struct reg_default *wm5102_patch;
+       const struct reg_sequence *wm5102_patch;
        int patch_size;
 
        switch (arizona->rev) {
index 12cad94b40354d8d548ab8974156f8c5c625f4db..26ce14f903fee5d6ea57c8d260f6c081ce93dca8 100644 (file)
@@ -21,7 +21,7 @@
 #define WM5110_NUM_AOD_ISR 2
 #define WM5110_NUM_ISR 5
 
-static const struct reg_default wm5110_reva_patch[] = {
+static const struct reg_sequence wm5110_reva_patch[] = {
        { 0x80, 0x3 },
        { 0x44, 0x20 },
        { 0x45, 0x40 },
@@ -134,7 +134,7 @@ static const struct reg_default wm5110_reva_patch[] = {
        { 0x209, 0x002A },
 };
 
-static const struct reg_default wm5110_revb_patch[] = {
+static const struct reg_sequence wm5110_revb_patch[] = {
        { 0x80, 0x3 },
        { 0x36e, 0x0210 },
        { 0x370, 0x0210 },
@@ -224,7 +224,7 @@ static const struct reg_default wm5110_revb_patch[] = {
        { 0x80, 0x0 },
 };
 
-static const struct reg_default wm5110_revd_patch[] = {
+static const struct reg_sequence wm5110_revd_patch[] = {
        { 0x80, 0x3 },
        { 0x80, 0x3 },
        { 0x393, 0x27 },
index 53ae5af5d6e4f97b88c19543a3ec81df09de64da..0f4169a3a5d4c181017ab22ac40a1cb1dfd1fad2 100644 (file)
@@ -243,21 +243,21 @@ static int wm8994_ldo_in_use(struct wm8994_pdata *pdata, int ldo)
 }
 #endif
 
-static const struct reg_default wm8994_revc_patch[] = {
+static const struct reg_sequence wm8994_revc_patch[] = {
        { 0x102, 0x3 },
        { 0x56, 0x3 },
        { 0x817, 0x0 },
        { 0x102, 0x0 },
 };
 
-static const struct reg_default wm8958_reva_patch[] = {
+static const struct reg_sequence wm8958_reva_patch[] = {
        { 0x102, 0x3 },
        { 0xcb, 0x81 },
        { 0x817, 0x0 },
        { 0x102, 0x0 },
 };
 
-static const struct reg_default wm1811_reva_patch[] = {
+static const struct reg_sequence wm1811_reva_patch[] = {
        { 0x102, 0x3 },
        { 0x56, 0xc07 },
        { 0x5d, 0x7e },
@@ -326,7 +326,7 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq)
 {
        struct wm8994_pdata *pdata;
        struct regmap_config *regmap_config;
-       const struct reg_default *regmap_patch = NULL;
+       const struct reg_sequence *regmap_patch = NULL;
        const char *devname;
        int ret, i, patch_regs = 0;
        int pulls = 0;
index c0c25d75aaccbf3a53218b71d5ea18f0b24c9d0d..cab2c68f17378eff6efd0a0da54153a094584b73 100644 (file)
@@ -17,7 +17,7 @@
 
 #include "arizona.h"
 
-static const struct reg_default wm8997_reva_patch[] = {
+static const struct reg_sequence wm8997_reva_patch[] = {
        { 0x80, 0x0003 },
        { 0x214, 0x0008 },
        { 0x458, 0x0000 },
index 59c55ea0f0b50c270d64bebe9dd6c25a717ca5ec..4a6759098769c6ad4902612bf3b2647fe0898f60 100644 (file)
@@ -50,6 +50,17 @@ struct reg_default {
        unsigned int def;
 };
 
+/**
+ * Register/value pairs for sequences of writes
+ *
+ * @reg: Register address.
+ * @def: Register value.
+ */
+struct reg_sequence {
+       unsigned int reg;
+       unsigned int def;
+};
+
 #ifdef CONFIG_REGMAP
 
 enum regmap_endian {
@@ -410,10 +421,10 @@ int regmap_raw_write(struct regmap *map, unsigned int reg,
                     const void *val, size_t val_len);
 int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
                        size_t val_count);
-int regmap_multi_reg_write(struct regmap *map, const struct reg_default *regs,
+int regmap_multi_reg_write(struct regmap *map, const struct reg_sequence *regs,
                        int num_regs);
 int regmap_multi_reg_write_bypassed(struct regmap *map,
-                                   const struct reg_default *regs,
+                                   const struct reg_sequence *regs,
                                    int num_regs);
 int regmap_raw_write_async(struct regmap *map, unsigned int reg,
                           const void *val, size_t val_len);
@@ -424,6 +435,8 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val,
                     size_t val_count);
 int regmap_update_bits(struct regmap *map, unsigned int reg,
                       unsigned int mask, unsigned int val);
+int regmap_write_bits(struct regmap *map, unsigned int reg,
+                      unsigned int mask, unsigned int val);
 int regmap_update_bits_async(struct regmap *map, unsigned int reg,
                             unsigned int mask, unsigned int val);
 int regmap_update_bits_check(struct regmap *map, unsigned int reg,
@@ -450,7 +463,7 @@ void regcache_mark_dirty(struct regmap *map);
 bool regmap_check_range_table(struct regmap *map, unsigned int reg,
                              const struct regmap_access_table *table);
 
-int regmap_register_patch(struct regmap *map, const struct reg_default *regs,
+int regmap_register_patch(struct regmap *map, const struct reg_sequence *regs,
                          int num_regs);
 int regmap_parse_val(struct regmap *map, const void *buf,
                                unsigned int *val);
@@ -503,6 +516,8 @@ int regmap_field_update_bits(struct regmap_field *field,
 
 int regmap_fields_write(struct regmap_field *field, unsigned int id,
                        unsigned int val);
+int regmap_fields_force_write(struct regmap_field *field, unsigned int id,
+                       unsigned int val);
 int regmap_fields_read(struct regmap_field *field, unsigned int id,
                       unsigned int *val);
 int regmap_fields_update_bits(struct regmap_field *field,  unsigned int id,
@@ -645,6 +660,13 @@ static inline int regmap_update_bits(struct regmap *map, unsigned int reg,
        return -EINVAL;
 }
 
+static inline int regmap_write_bits(struct regmap *map, unsigned int reg,
+                                    unsigned int mask, unsigned int val)
+{
+       WARN_ONCE(1, "regmap API is disabled");
+       return -EINVAL;
+}
+
 static inline int regmap_update_bits_async(struct regmap *map,
                                           unsigned int reg,
                                           unsigned int mask, unsigned int val)
index 4cecd0c175f607c7f3cae2a2fb03660f81131799..bb7b2ebfee7b9380e66f793cf5c6526e1aaf937f 100644 (file)
@@ -61,6 +61,14 @@ struct rsnd_src_platform_info {
 /*
  * flags
  */
+struct rsnd_ctu_platform_info {
+       u32 flags;
+};
+
+struct rsnd_mix_platform_info {
+       u32 flags;
+};
+
 struct rsnd_dvc_platform_info {
        u32 flags;
 };
@@ -68,6 +76,8 @@ struct rsnd_dvc_platform_info {
 struct rsnd_dai_path_info {
        struct rsnd_ssi_platform_info *ssi;
        struct rsnd_src_platform_info *src;
+       struct rsnd_ctu_platform_info *ctu;
+       struct rsnd_mix_platform_info *mix;
        struct rsnd_dvc_platform_info *dvc;
 };
 
@@ -93,6 +103,10 @@ struct rcar_snd_info {
        int ssi_info_nr;
        struct rsnd_src_platform_info *src_info;
        int src_info_nr;
+       struct rsnd_ctu_platform_info *ctu_info;
+       int ctu_info_nr;
+       struct rsnd_mix_platform_info *mix_info;
+       int mix_info_nr;
        struct rsnd_dvc_platform_info *dvc_info;
        int dvc_info_nr;
        struct rsnd_dai_platform_info *dai_info;
index 2b55115e94b21f10221f485b2facbafb32d42a81..8a2221ab3d10b97f5f7a97c21251264aa93eaa5b 100644 (file)
@@ -1366,7 +1366,7 @@ static void arizona_wm5102_set_dac_comp(struct snd_soc_codec *codec,
 {
        struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
        struct arizona *arizona = priv->arizona;
-       struct reg_default dac_comp[] = {
+       struct reg_sequence dac_comp[] = {
                { 0x80, 0x3 },
                { ARIZONA_DAC_COMP_1, 0 },
                { ARIZONA_DAC_COMP_2, 0 },
index 094201d1e692a2dae0dded9b76be2e436fbdf790..44c30fe3e3151dc6621c308da5c1f4759a6d3f65 100644 (file)
@@ -241,7 +241,7 @@ static const struct snd_soc_codec_driver soc_codec_dev_cs35l32 = {
 };
 
 /* Current and threshold powerup sequence Pg37 in datasheet */
-static const struct reg_default cs35l32_monitor_patch[] = {
+static const struct reg_sequence cs35l32_monitor_patch[] = {
 
        { 0x00, 0x99 },
        { 0x48, 0x17 },
index f4f41b280b890042cc8d2c717c3226ed1617ab02..b256424d3f9a3f0de105bf54533f01abbbb08958 100644 (file)
@@ -1067,7 +1067,7 @@ static const struct snd_soc_codec_driver soc_codec_dev_cs42l52 = {
 };
 
 /* Current and threshold powerup sequence Pg37 */
-static const struct reg_default cs42l52_threshold_patch[] = {
+static const struct reg_sequence cs42l52_threshold_patch[] = {
 
        { 0x00, 0x99 },
        { 0x3E, 0xBA },
index 457ed82d3e10ecf7d39e0e9bfc6ed70176bbc096..c7b3e927c606f866ec3a42b59cd1434e1c9eaaab 100644 (file)
@@ -1182,7 +1182,7 @@ static struct snd_soc_codec_driver soc_codec_dev_da7210 = {
 
 #if IS_ENABLED(CONFIG_I2C)
 
-static const struct reg_default da7210_regmap_i2c_patch[] = {
+static const struct reg_sequence da7210_regmap_i2c_patch[] = {
 
        /* System controller master disable */
        { DA7210_STARTUP1, 0x00 },
@@ -1268,7 +1268,7 @@ static struct i2c_driver da7210_i2c_driver = {
 
 #if defined(CONFIG_SPI_MASTER)
 
-static const struct reg_default da7210_regmap_spi_patch[] = {
+static const struct reg_sequence da7210_regmap_spi_patch[] = {
        /* Dummy read to give two pulses over nCS for SPI */
        { DA7210_AUX2, 0x00 },
        { DA7210_AUX2, 0x00 },
index 56650d6c2f537dd1a1d3c6c693bc7fdfaf48c627..aca479fa767027174be48390fd0dc93c3802d022 100644 (file)
  */
 
 #include <linux/module.h>
+#include <linux/regmap.h>
 
 #include "rl6231.h"
 
 /**
- * rl6231_calc_dmic_clk - Calculate the parameter of dmic.
+ * rl6231_get_pre_div - Return the value of pre divider.
+ *
+ * @map: map for setting.
+ * @reg: register.
+ * @sft: shift.
+ *
+ * Return the value of pre divider from given register value.
+ * Return negative error code for unexpected register value.
+ */
+int rl6231_get_pre_div(struct regmap *map, unsigned int reg, int sft)
+{
+       int pd, val;
+
+       regmap_read(map, reg, &val);
+
+       val = (val >> sft) & 0x7;
+
+       switch (val) {
+       case 0:
+       case 1:
+       case 2:
+       case 3:
+               pd = val + 1;
+               break;
+       case 4:
+               pd = 6;
+               break;
+       case 5:
+               pd = 8;
+               break;
+       case 6:
+               pd = 12;
+               break;
+       case 7:
+               pd = 16;
+               break;
+       default:
+               pd = -EINVAL;
+               break;
+       }
+
+       return pd;
+}
+EXPORT_SYMBOL_GPL(rl6231_get_pre_div);
+
+/**
+ * rl6231_calc_dmic_clk - Calculate the frequency divider parameter of dmic.
  *
  * @rate: base clock rate.
  *
- * Choose dmic clock between 1MHz and 3MHz.
- * It is better for clock to approximate 3MHz.
+ * Choose divider parameter that gives the highest possible DMIC frequency in
+ * 1MHz - 3MHz range.
  */
 int rl6231_calc_dmic_clk(int rate)
 {
-       int div[] = {2, 3, 4, 6, 8, 12}, idx = -EINVAL;
-       int i, red, bound, temp;
+       int div[] = {2, 3, 4, 6, 8, 12};
+       int i;
+
+       if (rate < 1000000 * div[0]) {
+               pr_warn("Base clock rate %d is too low\n", rate);
+               return -EINVAL;
+       }
 
-       red = 3000000 * 12;
        for (i = 0; i < ARRAY_SIZE(div); i++) {
-               bound = div[i] * 3000000;
-               if (rate > bound)
-                       continue;
-               temp = bound - rate;
-               if (temp < red) {
-                       red = temp;
-                       idx = i;
-               }
+               /* find divider that gives DMIC frequency below 3MHz */
+               if (3000000 * div[i] >= rate)
+                       return i;
        }
 
-       return idx;
+       pr_warn("Base clock rate %d is too high\n", rate);
+       return -EINVAL;
 }
 EXPORT_SYMBOL_GPL(rl6231_calc_dmic_clk);
 
+struct pll_calc_map {
+       unsigned int pll_in;
+       unsigned int pll_out;
+       int k;
+       int n;
+       int m;
+       bool m_bp;
+};
+
+static const struct pll_calc_map pll_preset_table[] = {
+       {19200000,  24576000,  3, 30, 3, false},
+};
+
 /**
  * rl6231_pll_calc - Calcualte PLL M/N/K code.
  * @freq_in: external clock provided to codec.
@@ -57,7 +117,7 @@ int rl6231_pll_calc(const unsigned int freq_in,
        const unsigned int freq_out, struct rl6231_pll_code *pll_code)
 {
        int max_n = RL6231_PLL_N_MAX, max_m = RL6231_PLL_M_MAX;
-       int k, red, n_t, pll_out, in_t, out_t;
+       int i, k, red, n_t, pll_out, in_t, out_t;
        int n = 0, m = 0, m_t = 0;
        int red_t = abs(freq_out - freq_in);
        bool bypass = false;
@@ -65,6 +125,18 @@ int rl6231_pll_calc(const unsigned int freq_in,
        if (RL6231_PLL_INP_MAX < freq_in || RL6231_PLL_INP_MIN > freq_in)
                return -EINVAL;
 
+       for (i = 0; i < ARRAY_SIZE(pll_preset_table); i++) {
+               if (freq_in == pll_preset_table[i].pll_in &&
+                       freq_out == pll_preset_table[i].pll_out) {
+                       k = pll_preset_table[i].k;
+                       m = pll_preset_table[i].m;
+                       n = pll_preset_table[i].n;
+                       bypass = pll_preset_table[i].m_bp;
+                       pr_debug("Use preset PLL parameter table\n");
+                       goto code_find;
+               }
+       }
+
        k = 100000000 / freq_out - 2;
        if (k > RL6231_PLL_K_MAX)
                k = RL6231_PLL_K_MAX;
index 0f7b057ed736fb685173a5a328ea62b8f3547fb0..4c77b441fba260c3c1be857ed5a76e2c4605c7f4 100644 (file)
@@ -30,5 +30,6 @@ int rl6231_calc_dmic_clk(int rate);
 int rl6231_pll_calc(const unsigned int freq_in,
        const unsigned int freq_out, struct rl6231_pll_code *pll_code);
 int rl6231_get_clk_info(int sclk, int rate);
+int rl6231_get_pre_div(struct regmap *map, unsigned int reg, int sft);
 
 #endif /* __RL6231_H__ */
index 4a658aba7372ef25041a729e3fae35a17a2ff454..bd9365885f73f508fa88de0908215473efaaddb3 100644 (file)
@@ -1108,7 +1108,7 @@ static const struct acpi_device_id rt286_acpi_match[] = {
 };
 MODULE_DEVICE_TABLE(acpi, rt286_acpi_match);
 
-static struct dmi_system_id force_combo_jack_table[] = {
+static const struct dmi_system_id force_combo_jack_table[] = {
        {
                .ident = "Intel Wilson Beach",
                .matches = {
@@ -1118,7 +1118,7 @@ static struct dmi_system_id force_combo_jack_table[] = {
        { }
 };
 
-static struct dmi_system_id dmi_dell_dino[] = {
+static const struct dmi_system_id dmi_dell_dino[] = {
        {
                .ident = "Dell Dino",
                .matches = {
@@ -1157,7 +1157,7 @@ static int rt286_i2c_probe(struct i2c_client *i2c,
        }
        if (val != RT286_VENDOR_ID && val != RT288_VENDOR_ID) {
                dev_err(&i2c->dev,
-                       "Device with ID register %x is not rt286\n", val);
+                       "Device with ID register %#x is not rt286\n", val);
                return -ENODEV;
        }
 
index e6691a12ca3dfea0e131c13038c27a08f84c61d9..a37223f7307adf8880ebfecee4414ba6449c25f4 100644 (file)
@@ -51,7 +51,7 @@ static const struct regmap_range_cfg rt5640_ranges[] = {
          .window_len = 0x1, },
 };
 
-static const struct reg_default init_list[] = {
+static const struct reg_sequence init_list[] = {
        {RT5640_PR_BASE + 0x3d, 0x3600},
        {RT5640_PR_BASE + 0x12, 0x0aa8},
        {RT5640_PR_BASE + 0x14, 0x0aaa},
@@ -459,10 +459,11 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w,
 {
        struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
-       int idx = -EINVAL;
-
-       idx = rl6231_calc_dmic_clk(rt5640->sysclk);
+       int idx, rate;
 
+       rate = rt5640->sysclk / rl6231_get_pre_div(rt5640->regmap,
+               RT5640_ADDA_CLK1, RT5640_I2S_PD1_SFT);
+       idx = rl6231_calc_dmic_clk(rate);
        if (idx < 0)
                dev_err(codec->dev, "Failed to set DMIC clock\n");
        else
index 36143402b2282dd9745ccb7fbaf19adfdcec4fda..1e70736cc970e6154291a06601de6e822f94f2ff 100644 (file)
@@ -55,7 +55,7 @@ static const struct regmap_range_cfg rt5645_ranges[] = {
        },
 };
 
-static const struct reg_default init_list[] = {
+static const struct reg_sequence init_list[] = {
        {RT5645_PR_BASE + 0x3d, 0x3600},
        {RT5645_PR_BASE + 0x1c, 0xfd20},
        {RT5645_PR_BASE + 0x20, 0x611f},
@@ -64,7 +64,7 @@ static const struct reg_default init_list[] = {
 };
 #define RT5645_INIT_REG_LEN ARRAY_SIZE(init_list)
 
-static const struct reg_default rt5650_init_list[] = {
+static const struct reg_sequence rt5650_init_list[] = {
        {0xf6,  0x0100},
 };
 
@@ -545,10 +545,11 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w,
 {
        struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
-       int idx = -EINVAL;
-
-       idx = rl6231_calc_dmic_clk(rt5645->sysclk);
+       int idx, rate;
 
+       rate = rt5645->sysclk / rl6231_get_pre_div(rt5645->regmap,
+               RT5645_ADDA_CLK1, RT5645_I2S_PD1_SFT);
+       idx = rl6231_calc_dmic_clk(rate);
        if (idx < 0)
                dev_err(codec->dev, "Failed to set DMIC clock\n");
        else
index 54acd286bd00b3d832b2000a72600df5444c625d..f2026a962e57dd5f657e746bda4e21002c495d5d 100644 (file)
@@ -46,7 +46,7 @@ static const struct regmap_range_cfg rt5651_ranges[] = {
          .window_len = 0x1, },
 };
 
-static const struct reg_default init_list[] = {
+static const struct reg_sequence init_list[] = {
        {RT5651_PR_BASE + 0x3d, 0x3e00},
 };
 
@@ -378,10 +378,11 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w,
 {
        struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct rt5651_priv *rt5651 = snd_soc_codec_get_drvdata(codec);
-       int idx = -EINVAL;
-
-       idx = rl6231_calc_dmic_clk(rt5651->sysclk);
+       int idx, rate;
 
+       rate = rt5651->sysclk / rl6231_get_pre_div(rt5651->regmap,
+               RT5651_ADDA_CLK1, RT5651_I2S_PD1_SFT);
+       idx = rl6231_calc_dmic_clk(rate);
        if (idx < 0)
                dev_err(codec->dev, "Failed to set DMIC clock\n");
        else
index d5bf49de39c5fbc5199156d4e15a0b92402bbd54..577251a7b110f19c0ce7194d8948babeb2e496b4 100644 (file)
@@ -51,7 +51,7 @@ static const struct regmap_range_cfg rt5670_ranges[] = {
          .window_len = 0x1, },
 };
 
-static const struct reg_default init_list[] = {
+static const struct reg_sequence init_list[] = {
        { RT5670_PR_BASE + 0x14, 0x9a8a },
        { RT5670_PR_BASE + 0x38, 0x3ba1 },
        { RT5670_PR_BASE + 0x3d, 0x3640 },
@@ -683,10 +683,11 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w,
 {
        struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec);
-       int idx = -EINVAL;
-
-       idx = rl6231_calc_dmic_clk(rt5670->sysclk);
+       int idx, rate;
 
+       rate = rt5670->sysclk / rl6231_get_pre_div(rt5670->regmap,
+               RT5670_ADDA_CLK1, RT5670_I2S_PD1_SFT);
+       idx = rl6231_calc_dmic_clk(rate);
        if (idx < 0)
                dev_err(codec->dev, "Failed to set DMIC clock\n");
        else
index 2313fbf99922f98681daccf598c4ab2dc91de71a..d9999336a7a211a91e5d8317f551011268a8bf1b 100644 (file)
@@ -54,7 +54,7 @@ static const struct regmap_range_cfg rt5677_ranges[] = {
        },
 };
 
-static const struct reg_default init_list[] = {
+static const struct reg_sequence init_list[] = {
        {RT5677_ASRC_12,        0x0018},
        {RT5677_PR_BASE + 0x3d, 0x364d},
        {RT5677_PR_BASE + 0x17, 0x4fc0},
@@ -917,8 +917,11 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w,
 {
        struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
        struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
-       int idx = rl6231_calc_dmic_clk(rt5677->lrck[RT5677_AIF1] << 8);
+       int idx, rate;
 
+       rate = rt5677->sysclk / rl6231_get_pre_div(rt5677->regmap,
+               RT5677_CLK_TREE_CTRL1, RT5677_I2S_PD1_SFT);
+       idx = rl6231_calc_dmic_clk(rate);
        if (idx < 0)
                dev_err(codec->dev, "Failed to set DMIC clock\n");
        else
index 125a93517cdb43731d2dbf21908d8be731b2ab66..1a82b19b26442e31eb38e8fa38287d9710aa3546 100644 (file)
@@ -1668,7 +1668,7 @@ static const struct i2c_device_id aic3x_i2c_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, aic3x_i2c_id);
 
-static const struct reg_default aic3007_class_d[] = {
+static const struct reg_sequence aic3007_class_d[] = {
        /* Class-D speaker driver init; datasheet p. 46 */
        { AIC3X_PAGE_SELECT, 0x0D },
        { 0xD, 0x0D },
index 878d43ad8564e69cb5832f069dcdde952311ee31..35199fc1f6cab12428503b34e39756d6926fa5e7 100644 (file)
@@ -897,7 +897,7 @@ static bool wm2200_readable_register(struct device *dev, unsigned int reg)
        }
 }
 
-static const struct reg_default wm2200_reva_patch[] = {
+static const struct reg_sequence wm2200_reva_patch[] = {
        { 0x07, 0x0003 },
        { 0x102, 0x0200 },
        { 0x203, 0x0084 },
index 1a951a4db08efd2e97a044360ada701bbf255251..3695b1dcbaf7d8e1b580a129a9ff3e4cc486b88f 100644 (file)
@@ -1247,7 +1247,7 @@ static const struct snd_soc_dapm_route wm5100_dapm_routes[] = {
        { "PWM2", NULL, "PWM2 Driver" },
 };
 
-static const struct reg_default wm5100_reva_patches[] = {
+static const struct reg_sequence wm5100_reva_patches[] = {
        { WM5100_AUDIO_IF_1_10, 0 },
        { WM5100_AUDIO_IF_1_11, 1 },
        { WM5100_AUDIO_IF_1_12, 2 },
index cbd18861c7928ba1c309c916cdb390801644e091..5c01707d49999a1398bcebac067888c5ea58c1da 100644 (file)
@@ -3495,7 +3495,7 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8962 = {
 };
 
 /* Improve power consumption for IN4 DC measurement mode */
-static const struct reg_default wm8962_dc_measure[] = {
+static const struct reg_sequence wm8962_dc_measure[] = {
        { 0xfd, 0x1 },
        { 0xcc, 0x40 },
        { 0xfd, 0 },
index 9638accb74b9038ff6b392e60e57f325a3a63433..ac9efd63dbef2a519a3b208675e2cdc76cb585c5 100644 (file)
@@ -1595,7 +1595,7 @@ static int wm8993_resume(struct snd_soc_codec *codec)
 #endif
 
 /* Tune DC servo configuration */
-static const struct reg_default wm8993_regmap_patch[] = {
+static const struct reg_sequence wm8993_regmap_patch[] = {
        { 0x44, 3 },
        { 0x56, 3 },
        { 0x44, 0 },
index cc26f81ee4ffbf14bee0d20d1fbf8687ce2476e3..26567b10393a5074e8d9b217f2dcd700834420dd 100644 (file)
@@ -223,7 +223,6 @@ static struct platform_driver snd_rk_mc_driver = {
        .probe = snd_rk_mc_probe,
        .driver = {
                .name = DRV_NAME,
-               .owner = THIS_MODULE,
                .pm = &snd_soc_pm_ops,
                .of_match_table = rockchip_max98090_of_match,
        },
index 09402799c8dccbb6a87af2e9fccbe765d4474e8c..68c62e4c23168a1e9e8656956ee9b83584892d18 100644 (file)
@@ -118,7 +118,7 @@ static int rk_init(struct snd_soc_pcm_runtime *runtime)
                                    SND_JACK_BTN_0 | SND_JACK_BTN_1 |
                                    SND_JACK_BTN_2 | SND_JACK_BTN_3,
                                    &headset_jack, NULL, 0);
-       if (!ret) {
+       if (ret) {
                dev_err(card->dev, "New Headset Jack failed! (%d)\n", ret);
                return ret;
        }
@@ -212,7 +212,6 @@ static struct platform_driver snd_rk_mc_driver = {
        .probe = snd_rk_mc_probe,
        .driver = {
                .name = DRV_NAME,
-               .owner = THIS_MODULE,
                .pm = &snd_soc_pm_ops,
                .of_match_table = rockchip_rt5645_of_match,
        },
index f1b445173fba7857e4dcd440ce75c5d8f21d33f3..8b258501aa357e78630bdf73a4be091fa5fb1f6c 100644 (file)
@@ -1,4 +1,4 @@
-snd-soc-rcar-objs      := core.o gen.o dma.o src.o adg.o ssi.o dvc.o
+snd-soc-rcar-objs      := core.o gen.o dma.o adg.o ssi.o src.o ctu.o mix.o dvc.o
 obj-$(CONFIG_SND_SOC_RCAR)     += snd-soc-rcar.o
 
 snd-soc-rsrc-card-objs := rsrc-card.o
index f1e5920654f6ff74803b770ef31d66579fd9b8df..f3feed5ce9b65ba67d936a399a4a06f91cf77db7 100644 (file)
@@ -203,9 +203,9 @@ int rsnd_io_is_working(struct rsnd_dai_stream *io)
 }
 
 /*
- *     settting function
+ *     ADINR function
  */
-u32 rsnd_get_adinr(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
+u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
 {
        struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
        struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
@@ -227,6 +227,64 @@ u32 rsnd_get_adinr(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
        return adinr;
 }
 
+u32 rsnd_get_adinr_chan(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
+{
+       struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+       struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+       struct device *dev = rsnd_priv_to_dev(priv);
+       u32 chan = runtime->channels;
+
+       switch (chan) {
+       case 1:
+       case 2:
+       case 4:
+       case 6:
+       case 8:
+               break;
+       default:
+               dev_warn(dev, "not supported channel\n");
+               chan = 0;
+               break;
+       }
+
+       return chan;
+}
+
+/*
+ *     DALIGN function
+ */
+u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
+{
+       struct rsnd_mod *src = rsnd_io_to_mod_src(io);
+       struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io);
+       struct rsnd_mod *target = src ? src : ssi;
+       struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+       u32 val = 0x76543210;
+       u32 mask = ~0;
+
+       mask <<= runtime->channels * 4;
+       val = val & mask;
+
+       switch (runtime->sample_bits) {
+       case 16:
+               val |= 0x67452301 & ~mask;
+               break;
+       case 32:
+               val |= 0x76543210 & ~mask;
+               break;
+       }
+
+       /*
+        * exchange channeles on SRC if possible,
+        * otherwise, R/L volume settings on DVC
+        * changes inverted channels
+        */
+       if (mod == target)
+               return val;
+       else
+               return 0x76543210;
+}
+
 /*
  *     rsnd_dai functions
  */
@@ -242,9 +300,9 @@ u32 rsnd_get_adinr(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
        if (val == __rsnd_mod_call_##func) {                            \
                called = 1;                                             \
                ret = (mod)->ops->func(mod, io, param);                 \
-               mod->status = (mod->status & ~mask) +                   \
-                       (add << __rsnd_mod_shift_##func);               \
        }                                                               \
+       mod->status = (mod->status & ~mask) +                           \
+               (add << __rsnd_mod_shift_##func);                       \
        dev_dbg(dev, "%s[%d] 0x%08x %s\n",                              \
                rsnd_mod_name(mod), rsnd_mod_id(mod), mod->status,      \
                called ? #func : "");                                   \
@@ -274,21 +332,21 @@ u32 rsnd_get_adinr(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
 static int rsnd_dai_connect(struct rsnd_mod *mod,
                            struct rsnd_dai_stream *io)
 {
+       struct rsnd_priv *priv;
+       struct device *dev;
+
        if (!mod)
                return -EIO;
 
-       if (io->mod[mod->type]) {
-               struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
-               struct device *dev = rsnd_priv_to_dev(priv);
-
-               dev_err(dev, "%s[%d] is not empty\n",
-                       rsnd_mod_name(mod),
-                       rsnd_mod_id(mod));
-               return -EIO;
-       }
+       priv = rsnd_mod_to_priv(mod);
+       dev = rsnd_priv_to_dev(priv);
 
        io->mod[mod->type] = mod;
 
+       dev_dbg(dev, "%s[%d] is connected to io (%s)\n",
+               rsnd_mod_name(mod), rsnd_mod_id(mod),
+               rsnd_io_is_play(io) ? "Playback" : "Capture");
+
        return 0;
 }
 
@@ -517,7 +575,7 @@ static const struct snd_soc_dai_ops rsnd_soc_dai_ops = {
        .set_fmt        = rsnd_soc_dai_set_fmt,
 };
 
-#define rsnd_path_parse(priv, io, type)                                \
+#define rsnd_path_add(priv, io, type)                          \
 ({                                                             \
        struct rsnd_mod *mod;                                   \
        int ret = 0;                                            \
@@ -533,7 +591,7 @@ static const struct snd_soc_dai_ops rsnd_soc_dai_ops = {
        ret;                                                    \
 })
 
-#define rsnd_path_break(priv, io, type)                                \
+#define rsnd_path_remove(priv, io, type)                       \
 {                                                              \
        struct rsnd_mod *mod;                                   \
        int id = -1;                                            \
@@ -547,6 +605,79 @@ static const struct snd_soc_dai_ops rsnd_soc_dai_ops = {
        }                                                       \
 }
 
+void rsnd_path_parse(struct rsnd_priv *priv,
+                    struct rsnd_dai_stream *io)
+{
+       struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io);
+       struct rsnd_mod *mix = rsnd_io_to_mod_mix(io);
+       struct rsnd_mod *src = rsnd_io_to_mod_src(io);
+       struct rsnd_mod *cmd;
+       struct device *dev = rsnd_priv_to_dev(priv);
+       u32 data;
+
+       /* Gen1 is not supported */
+       if (rsnd_is_gen1(priv))
+               return;
+
+       if (!mix && !dvc)
+               return;
+
+       if (mix) {
+               struct rsnd_dai *rdai;
+               int i;
+               u32 path[] = {
+                       [0] = 0,
+                       [1] = 1 << 0,
+                       [2] = 0,
+                       [3] = 0,
+                       [4] = 0,
+                       [5] = 1 << 8
+               };
+
+               /*
+                * it is assuming that integrater is well understanding about
+                * data path. Here doesn't check impossible connection,
+                * like src2 + src5
+                */
+               data = 0;
+               for_each_rsnd_dai(rdai, priv, i) {
+                       io = &rdai->playback;
+                       if (mix == rsnd_io_to_mod_mix(io))
+                               data |= path[rsnd_mod_id(src)];
+
+                       io = &rdai->capture;
+                       if (mix == rsnd_io_to_mod_mix(io))
+                               data |= path[rsnd_mod_id(src)];
+               }
+
+               /*
+                * We can't use ctu = rsnd_io_ctu() here.
+                * Since, ID of dvc/mix are 0 or 1 (= same as CMD number)
+                * but ctu IDs are 0 - 7 (= CTU00 - CTU13)
+                */
+               cmd = mix;
+       } else {
+               u32 path[] = {
+                       [0] = 0x30000,
+                       [1] = 0x30001,
+                       [2] = 0x40000,
+                       [3] = 0x10000,
+                       [4] = 0x20000,
+                       [5] = 0x40100
+               };
+
+               data = path[rsnd_mod_id(src)];
+
+               cmd = dvc;
+       }
+
+       dev_dbg(dev, "ctu/mix path = 0x%08x", data);
+
+       rsnd_mod_write(cmd, CMD_ROUTE_SLCT, data);
+
+       rsnd_mod_write(cmd, CMD_CTRL, 0x10);
+}
+
 static int rsnd_path_init(struct rsnd_priv *priv,
                          struct rsnd_dai *rdai,
                          struct rsnd_dai_stream *io)
@@ -564,18 +695,28 @@ static int rsnd_path_init(struct rsnd_priv *priv,
         * using fixed path.
         */
 
+       /* SSI */
+       ret = rsnd_path_add(priv, io, ssi);
+       if (ret < 0)
+               return ret;
+
        /* SRC */
-       ret = rsnd_path_parse(priv, io, src);
+       ret = rsnd_path_add(priv, io, src);
        if (ret < 0)
                return ret;
 
-       /* SSI */
-       ret = rsnd_path_parse(priv, io, ssi);
+       /* CTU */
+       ret = rsnd_path_add(priv, io, ctu);
+       if (ret < 0)
+               return ret;
+
+       /* MIX */
+       ret = rsnd_path_add(priv, io, mix);
        if (ret < 0)
                return ret;
 
        /* DVC */
-       ret = rsnd_path_parse(priv, io, dvc);
+       ret = rsnd_path_add(priv, io, dvc);
        if (ret < 0)
                return ret;
 
@@ -589,13 +730,15 @@ static void rsnd_of_parse_dai(struct platform_device *pdev,
        struct device_node *dai_node,   *dai_np;
        struct device_node *ssi_node,   *ssi_np;
        struct device_node *src_node,   *src_np;
+       struct device_node *ctu_node,   *ctu_np;
+       struct device_node *mix_node,   *mix_np;
        struct device_node *dvc_node,   *dvc_np;
        struct device_node *playback, *capture;
        struct rsnd_dai_platform_info *dai_info;
        struct rcar_snd_info *info = rsnd_priv_to_info(priv);
        struct device *dev = &pdev->dev;
        int nr, i;
-       int dai_i, ssi_i, src_i, dvc_i;
+       int dai_i, ssi_i, src_i, ctu_i, mix_i, dvc_i;
 
        if (!of_data)
                return;
@@ -621,6 +764,8 @@ static void rsnd_of_parse_dai(struct platform_device *pdev,
 
        ssi_node = of_get_child_by_name(dev->of_node, "rcar_sound,ssi");
        src_node = of_get_child_by_name(dev->of_node, "rcar_sound,src");
+       ctu_node = of_get_child_by_name(dev->of_node, "rcar_sound,ctu");
+       mix_node = of_get_child_by_name(dev->of_node, "rcar_sound,mix");
        dvc_node = of_get_child_by_name(dev->of_node, "rcar_sound,dvc");
 
 #define mod_parse(name)                                                        \
@@ -657,6 +802,8 @@ if (name##_node) {                                                  \
 
                        mod_parse(ssi);
                        mod_parse(src);
+                       mod_parse(ctu);
+                       mod_parse(mix);
                        mod_parse(dvc);
 
                        of_node_put(playback);
@@ -1033,8 +1180,8 @@ static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv,
                /*
                 * remove SRC/DVC from DAI,
                 */
-               rsnd_path_break(priv, io, src);
-               rsnd_path_break(priv, io, dvc);
+               rsnd_path_remove(priv, io, src);
+               rsnd_path_remove(priv, io, dvc);
 
                /*
                 * fallback
@@ -1069,6 +1216,8 @@ static int rsnd_probe(struct platform_device *pdev)
                rsnd_dma_probe,
                rsnd_ssi_probe,
                rsnd_src_probe,
+               rsnd_ctu_probe,
+               rsnd_mix_probe,
                rsnd_dvc_probe,
                rsnd_adg_probe,
                rsnd_dai_probe,
@@ -1164,6 +1313,8 @@ static int rsnd_remove(struct platform_device *pdev)
                              struct rsnd_priv *priv) = {
                rsnd_ssi_remove,
                rsnd_src_remove,
+               rsnd_ctu_remove,
+               rsnd_mix_remove,
                rsnd_dvc_remove,
        };
        int ret = 0, i;
diff --git a/sound/soc/sh/rcar/ctu.c b/sound/soc/sh/rcar/ctu.c
new file mode 100644 (file)
index 0000000..05498bb
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * ctu.c
+ *
+ * Copyright (c) 2015 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ *
+ * 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 "rsnd.h"
+
+#define CTU_NAME_SIZE  16
+#define CTU_NAME "ctu"
+
+struct rsnd_ctu {
+       struct rsnd_ctu_platform_info *info; /* rcar_snd.h */
+       struct rsnd_mod mod;
+};
+
+#define rsnd_ctu_nr(priv) ((priv)->ctu_nr)
+#define for_each_rsnd_ctu(pos, priv, i)                                        \
+       for ((i) = 0;                                                   \
+            ((i) < rsnd_ctu_nr(priv)) &&                               \
+                    ((pos) = (struct rsnd_ctu *)(priv)->ctu + i);      \
+            i++)
+
+#define rsnd_ctu_initialize_lock(mod)  __rsnd_ctu_initialize_lock(mod, 1)
+#define rsnd_ctu_initialize_unlock(mod)        __rsnd_ctu_initialize_lock(mod, 0)
+static void __rsnd_ctu_initialize_lock(struct rsnd_mod *mod, u32 enable)
+{
+       rsnd_mod_write(mod, CTU_CTUIR, enable);
+}
+
+static int rsnd_ctu_init(struct rsnd_mod *mod,
+                        struct rsnd_dai_stream *io,
+                        struct rsnd_priv *priv)
+{
+       rsnd_mod_hw_start(mod);
+
+       rsnd_ctu_initialize_lock(mod);
+
+       rsnd_mod_write(mod, CTU_ADINR, rsnd_get_adinr_chan(mod, io));
+
+       rsnd_ctu_initialize_unlock(mod);
+
+       return 0;
+}
+
+static int rsnd_ctu_quit(struct rsnd_mod *mod,
+                        struct rsnd_dai_stream *io,
+                        struct rsnd_priv *priv)
+{
+       rsnd_mod_hw_stop(mod);
+
+       return 0;
+}
+
+static struct rsnd_mod_ops rsnd_ctu_ops = {
+       .name           = CTU_NAME,
+       .init           = rsnd_ctu_init,
+       .quit           = rsnd_ctu_quit,
+};
+
+struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id)
+{
+       if (WARN_ON(id < 0 || id >= rsnd_ctu_nr(priv)))
+               id = 0;
+
+       return &((struct rsnd_ctu *)(priv->ctu) + id)->mod;
+}
+
+static void rsnd_of_parse_ctu(struct platform_device *pdev,
+                      const struct rsnd_of_data *of_data,
+                      struct rsnd_priv *priv)
+{
+       struct device_node *node;
+       struct rsnd_ctu_platform_info *ctu_info;
+       struct rcar_snd_info *info = rsnd_priv_to_info(priv);
+       struct device *dev = &pdev->dev;
+       int nr;
+
+       if (!of_data)
+               return;
+
+       node = of_get_child_by_name(dev->of_node, "rcar_sound,ctu");
+       if (!node)
+               return;
+
+       nr = of_get_child_count(node);
+       if (!nr)
+               goto rsnd_of_parse_ctu_end;
+
+       ctu_info = devm_kzalloc(dev,
+                               sizeof(struct rsnd_ctu_platform_info) * nr,
+                               GFP_KERNEL);
+       if (!ctu_info) {
+               dev_err(dev, "ctu info allocation error\n");
+               goto rsnd_of_parse_ctu_end;
+       }
+
+       info->ctu_info          = ctu_info;
+       info->ctu_info_nr       = nr;
+
+rsnd_of_parse_ctu_end:
+       of_node_put(node);
+
+}
+
+int rsnd_ctu_probe(struct platform_device *pdev,
+                  const struct rsnd_of_data *of_data,
+                  struct rsnd_priv *priv)
+{
+       struct rcar_snd_info *info = rsnd_priv_to_info(priv);
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct rsnd_ctu *ctu;
+       struct clk *clk;
+       char name[CTU_NAME_SIZE];
+       int i, nr, ret;
+
+       /* This driver doesn't support Gen1 at this point */
+       if (rsnd_is_gen1(priv)) {
+               dev_warn(dev, "CTU is not supported on Gen1\n");
+               return -EINVAL;
+       }
+
+       rsnd_of_parse_ctu(pdev, of_data, priv);
+
+       nr = info->ctu_info_nr;
+       if (!nr)
+               return 0;
+
+       ctu = devm_kzalloc(dev, sizeof(*ctu) * nr, GFP_KERNEL);
+       if (!ctu)
+               return -ENOMEM;
+
+       priv->ctu_nr    = nr;
+       priv->ctu       = ctu;
+
+       for_each_rsnd_ctu(ctu, priv, i) {
+               /*
+                * CTU00, CTU01, CTU02, CTU03 => CTU0
+                * CTU10, CTU11, CTU12, CTU13 => CTU1
+                */
+               snprintf(name, CTU_NAME_SIZE, "%s.%d",
+                        CTU_NAME, i / 4);
+
+               clk = devm_clk_get(dev, name);
+               if (IS_ERR(clk))
+                       return PTR_ERR(clk);
+
+               ctu->info = &info->ctu_info[i];
+
+               ret = rsnd_mod_init(priv, &ctu->mod, &rsnd_ctu_ops,
+                                   clk, RSND_MOD_CTU, i);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+void rsnd_ctu_remove(struct platform_device *pdev,
+                    struct rsnd_priv *priv)
+{
+       struct rsnd_ctu *ctu;
+       int i;
+
+       for_each_rsnd_ctu(ctu, priv, i) {
+               rsnd_mod_quit(&ctu->mod);
+       }
+}
index d306e298c63dce269ec3b790a8ac225516181d1f..bfbb8a5e93bdce6c5c70092565869bf446233416 100644 (file)
@@ -27,6 +27,15 @@ struct rsnd_dma_ctrl {
        int dmapp_num;
 };
 
+struct rsnd_dma_ops {
+       char *name;
+       void (*start)(struct rsnd_dai_stream *io, struct rsnd_dma *dma);
+       void (*stop)(struct rsnd_dai_stream *io, struct rsnd_dma *dma);
+       int (*init)(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id,
+                   struct rsnd_mod *mod_from, struct rsnd_mod *mod_to);
+       void (*quit)(struct rsnd_dai_stream *io, struct rsnd_dma *dma);
+};
+
 #define rsnd_priv_to_dmac(p)   ((struct rsnd_dma_ctrl *)(p)->dma)
 
 /*
@@ -168,7 +177,7 @@ static int rsnd_dmaen_init(struct rsnd_dai_stream *io,
                dma_cap_set(DMA_SLAVE, mask);
 
                dmaen->chan = dma_request_channel(mask, shdma_chan_filter,
-                                                 (void *)id);
+                                                 (void *)(uintptr_t)id);
        }
        if (IS_ERR_OR_NULL(dmaen->chan)) {
                dmaen->chan = NULL;
@@ -182,7 +191,8 @@ static int rsnd_dmaen_init(struct rsnd_dai_stream *io,
        cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
        cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
 
-       dev_dbg(dev, "dma : %pad -> %pad\n",
+       dev_dbg(dev, "%s %pad -> %pad\n",
+               dma->ops->name,
                &cfg.src_addr, &cfg.dst_addr);
 
        ret = dmaengine_slave_config(dmaen->chan, &cfg);
@@ -215,6 +225,7 @@ static void rsnd_dmaen_quit(struct rsnd_dai_stream *io, struct rsnd_dma *dma)
 }
 
 static struct rsnd_dma_ops rsnd_dmaen_ops = {
+       .name   = "audmac",
        .start  = rsnd_dmaen_start,
        .stop   = rsnd_dmaen_stop,
        .init   = rsnd_dmaen_init,
@@ -360,6 +371,7 @@ static int rsnd_dmapp_init(struct rsnd_dai_stream *io,
 }
 
 static struct rsnd_dma_ops rsnd_dmapp_ops = {
+       .name   = "audmac-pp",
        .start  = rsnd_dmapp_start,
        .stop   = rsnd_dmapp_stop,
        .init   = rsnd_dmapp_init,
@@ -414,7 +426,9 @@ rsnd_gen2_dma_addr(struct rsnd_dai_stream *io,
        phys_addr_t src_reg = rsnd_gen_get_phy_addr(priv, RSND_GEN2_SCU);
        int is_ssi = !!(rsnd_io_to_mod_ssi(io) == mod);
        int use_src = !!rsnd_io_to_mod_src(io);
-       int use_dvc = !!rsnd_io_to_mod_dvc(io);
+       int use_cmd = !!rsnd_io_to_mod_dvc(io) ||
+                     !!rsnd_io_to_mod_mix(io) ||
+                     !!rsnd_io_to_mod_ctu(io);
        int id = rsnd_mod_id(mod);
        struct dma_addr {
                dma_addr_t out_addr;
@@ -452,7 +466,7 @@ rsnd_gen2_dma_addr(struct rsnd_dai_stream *io,
        };
 
        /* it shouldn't happen */
-       if (use_dvc && !use_src)
+       if (use_cmd && !use_src)
                dev_err(dev, "DVC is selected without SRC\n");
 
        /* use SSIU or SSI ? */
@@ -460,8 +474,8 @@ rsnd_gen2_dma_addr(struct rsnd_dai_stream *io,
                is_ssi++;
 
        return (is_from) ?
-               dma_addrs[is_ssi][is_play][use_src + use_dvc].out_addr :
-               dma_addrs[is_ssi][is_play][use_src + use_dvc].in_addr;
+               dma_addrs[is_ssi][is_play][use_src + use_cmd].out_addr :
+               dma_addrs[is_ssi][is_play][use_src + use_cmd].in_addr;
 }
 
 static dma_addr_t rsnd_dma_addr(struct rsnd_dai_stream *io,
@@ -482,7 +496,7 @@ static dma_addr_t rsnd_dma_addr(struct rsnd_dai_stream *io,
        return rsnd_gen2_dma_addr(io, mod, is_play, is_from);
 }
 
-#define MOD_MAX 4 /* MEM/SSI/SRC/DVC */
+#define MOD_MAX (RSND_MOD_MAX + 1) /* +Memory */
 static void rsnd_dma_of_path(struct rsnd_dma *dma,
                             struct rsnd_dai_stream *io,
                             int is_play,
@@ -492,55 +506,81 @@ static void rsnd_dma_of_path(struct rsnd_dma *dma,
        struct rsnd_mod *this = rsnd_dma_to_mod(dma);
        struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io);
        struct rsnd_mod *src = rsnd_io_to_mod_src(io);
+       struct rsnd_mod *ctu = rsnd_io_to_mod_ctu(io);
+       struct rsnd_mod *mix = rsnd_io_to_mod_mix(io);
        struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io);
        struct rsnd_mod *mod[MOD_MAX];
-       int i, index;
+       struct rsnd_mod *mod_start, *mod_end;
+       struct rsnd_priv *priv = rsnd_mod_to_priv(this);
+       struct device *dev = rsnd_priv_to_dev(priv);
+       int nr, i;
 
+       if (!ssi)
+               return;
 
-       for (i = 0; i < MOD_MAX; i++)
+       nr = 0;
+       for (i = 0; i < MOD_MAX; i++) {
                mod[i] = NULL;
+               nr += !!rsnd_io_to_mod(io, i);
+       }
 
        /*
-        * in play case...
+        * [S] -*-> [E]
+        * [S] -*-> SRC -o-> [E]
+        * [S] -*-> SRC -> DVC -o-> [E]
+        * [S] -*-> SRC -> CTU -> MIX -> DVC -o-> [E]
         *
-        * src -> dst
+        * playback     [S] = mem
+        *              [E] = SSI
         *
-        * mem -> SSI
-        * mem -> SRC -> SSI
-        * mem -> SRC -> DVC -> SSI
+        * capture      [S] = SSI
+        *              [E] = mem
+        *
+        * -*->         Audio DMAC
+        * -o->         Audio DMAC peri peri
         */
-       mod[0] = NULL; /* for "mem" */
-       index = 1;
-       for (i = 1; i < MOD_MAX; i++) {
-               if (!src) {
-                       mod[i] = ssi;
-               } else if (!dvc) {
-                       mod[i] = src;
-                       src = NULL;
-               } else {
-                       if ((!is_play) && (this == src))
-                               this = dvc;
+       mod_start       = (is_play) ? NULL : ssi;
+       mod_end         = (is_play) ? ssi  : NULL;
 
-                       mod[i] = (is_play) ? src : dvc;
-                       i++;
-                       mod[i] = (is_play) ? dvc : src;
+       mod[0] = mod_start;
+       for (i = 1; i < nr; i++) {
+               if (src) {
+                       mod[i] = src;
                        src = NULL;
+               } else if (ctu) {
+                       mod[i] = ctu;
+                       ctu = NULL;
+               } else if (mix) {
+                       mod[i] = mix;
+                       mix = NULL;
+               } else if (dvc) {
+                       mod[i] = dvc;
                        dvc = NULL;
                }
-
-               if (mod[i] == this)
-                       index = i;
-
-               if (mod[i] == ssi)
-                       break;
        }
+       mod[i] = mod_end;
 
-       if (is_play) {
-               *mod_from = mod[index - 1];
-               *mod_to   = mod[index];
+       /*
+        *              | SSI | SRC |
+        * -------------+-----+-----+
+        *  is_play     |  o  |  *  |
+        * !is_play     |  *  |  o  |
+        */
+       if ((this == ssi) == (is_play)) {
+               *mod_from       = mod[nr - 1];
+               *mod_to         = mod[nr];
        } else {
-               *mod_from = mod[index];
-               *mod_to   = mod[index - 1];
+               *mod_from       = mod[0];
+               *mod_to         = mod[1];
+       }
+
+       dev_dbg(dev, "module connection (this is %s[%d])\n",
+               rsnd_mod_name(this), rsnd_mod_id(this));
+       for (i = 0; i <= nr; i++) {
+               dev_dbg(dev, "  %s[%d]%s\n",
+                      rsnd_mod_name(mod[i]), rsnd_mod_id(mod[i]),
+                      (mod[i] == *mod_from) ? " from" :
+                      (mod[i] == *mod_to)   ? " to" : "");
        }
 }
 
@@ -568,10 +608,11 @@ void rsnd_dma_quit(struct rsnd_dai_stream *io, struct rsnd_dma *dma)
 
 int rsnd_dma_init(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id)
 {
-       struct rsnd_mod *mod_from;
-       struct rsnd_mod *mod_to;
+       struct rsnd_mod *mod_from = NULL;
+       struct rsnd_mod *mod_to = NULL;
        struct rsnd_priv *priv = rsnd_io_to_priv(io);
        struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv);
+       struct device *dev = rsnd_priv_to_dev(priv);
        int is_play = rsnd_io_is_play(io);
 
        /*
@@ -598,6 +639,11 @@ int rsnd_dma_init(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id)
        if (rsnd_is_gen1(priv))
                dma->ops = &rsnd_dmaen_ops;
 
+       dev_dbg(dev, "%s %s[%d] -> %s[%d]\n",
+               dma->ops->name,
+               rsnd_mod_name(mod_from), rsnd_mod_id(mod_from),
+               rsnd_mod_name(mod_to),   rsnd_mod_id(mod_to));
+
        return dma->ops->init(io, dma, id, mod_from, mod_to);
 }
 
index 36fc020cbc1803cbec2a7e1a225ae8690ea84a98..57796387d482303bc84c29212dfed167685ae6fe 100644 (file)
@@ -24,6 +24,7 @@ struct rsnd_dvc {
        struct rsnd_kctrl_cfg_s rdown;  /* Ramp Rate Down */
 };
 
+#define rsnd_dvc_nr(priv) ((priv)->dvc_nr)
 #define rsnd_dvc_of_node(priv) \
        of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,dvc")
 
@@ -63,6 +64,19 @@ static const char * const dvc_ramp_rate[] = {
        "0.125 dB/8192 steps",   /* 10111 */
 };
 
+static void rsnd_dvc_soft_reset(struct rsnd_mod *mod)
+{
+       rsnd_mod_write(mod, DVC_SWRSR, 0);
+       rsnd_mod_write(mod, DVC_SWRSR, 1);
+}
+
+#define rsnd_dvc_initialize_lock(mod)  __rsnd_dvc_initialize_lock(mod, 1)
+#define rsnd_dvc_initialize_unlock(mod)        __rsnd_dvc_initialize_lock(mod, 0)
+static void __rsnd_dvc_initialize_lock(struct rsnd_mod *mod, u32 enable)
+{
+       rsnd_mod_write(mod, DVC_DVUIR, enable);
+}
+
 static void rsnd_dvc_volume_update(struct rsnd_dai_stream *io,
                                   struct rsnd_mod *mod)
 {
@@ -135,49 +149,24 @@ static int rsnd_dvc_remove_gen2(struct rsnd_mod *mod,
        return 0;
 }
 
-static int rsnd_dvc_init(struct rsnd_mod *dvc_mod,
+static int rsnd_dvc_init(struct rsnd_mod *mod,
                         struct rsnd_dai_stream *io,
                         struct rsnd_priv *priv)
 {
-       struct rsnd_mod *src_mod = rsnd_io_to_mod_src(io);
-       struct device *dev = rsnd_priv_to_dev(priv);
-       int dvc_id = rsnd_mod_id(dvc_mod);
-       int src_id = rsnd_mod_id(src_mod);
-       u32 route[] = {
-               [0] = 0x30000,
-               [1] = 0x30001,
-               [2] = 0x40000,
-               [3] = 0x10000,
-               [4] = 0x20000,
-               [5] = 0x40100
-       };
-
-       if (src_id >= ARRAY_SIZE(route)) {
-               dev_err(dev, "DVC%d isn't connected to SRC%d\n", dvc_id, src_id);
-               return -EINVAL;
-       }
-
-       rsnd_mod_hw_start(dvc_mod);
+       rsnd_mod_hw_start(mod);
 
-       /*
-        * fixme
-        * it doesn't support CTU/MIX
-        */
-       rsnd_mod_write(dvc_mod, CMD_ROUTE_SLCT, route[src_id]);
+       rsnd_dvc_soft_reset(mod);
 
-       rsnd_mod_write(dvc_mod, DVC_SWRSR, 0);
-       rsnd_mod_write(dvc_mod, DVC_SWRSR, 1);
+       rsnd_dvc_initialize_lock(mod);
 
-       rsnd_mod_write(dvc_mod, DVC_DVUIR, 1);
+       rsnd_path_parse(priv, io);
 
-       rsnd_mod_write(dvc_mod, DVC_ADINR, rsnd_get_adinr(dvc_mod, io));
+       rsnd_mod_write(mod, DVC_ADINR, rsnd_get_adinr_bit(mod, io));
 
        /* ch0/ch1 Volume */
-       rsnd_dvc_volume_update(io, dvc_mod);
+       rsnd_dvc_volume_update(io, mod);
 
-       rsnd_mod_write(dvc_mod, DVC_DVUIR, 0);
-
-       rsnd_adg_set_cmd_timsel_gen2(dvc_mod, io);
+       rsnd_adg_set_cmd_timsel_gen2(mod, io);
 
        return 0;
 }
@@ -195,6 +184,8 @@ static int rsnd_dvc_start(struct rsnd_mod *mod,
                          struct rsnd_dai_stream *io,
                          struct rsnd_priv *priv)
 {
+       rsnd_dvc_initialize_unlock(mod);
+
        rsnd_mod_write(mod, CMD_CTRL, 0x10);
 
        return 0;
@@ -341,23 +332,21 @@ int rsnd_dvc_probe(struct platform_device *pdev,
        char name[RSND_DVC_NAME_SIZE];
        int i, nr, ret;
 
-       rsnd_of_parse_dvc(pdev, of_data, priv);
-
-       nr = info->dvc_info_nr;
-       if (!nr)
-               return 0;
-
        /* This driver doesn't support Gen1 at this point */
        if (rsnd_is_gen1(priv)) {
                dev_warn(dev, "CMD is not supported on Gen1\n");
                return -EINVAL;
        }
 
+       rsnd_of_parse_dvc(pdev, of_data, priv);
+
+       nr = info->dvc_info_nr;
+       if (!nr)
+               return 0;
+
        dvc     = devm_kzalloc(dev, sizeof(*dvc) * nr, GFP_KERNEL);
-       if (!dvc) {
-               dev_err(dev, "CMD allocate failed\n");
+       if (!dvc)
                return -ENOMEM;
-       }
 
        priv->dvc_nr    = nr;
        priv->dvc       = dvc;
index 8c7dc51b1c4fd8a767a5717a651faed17e68234a..f04d17bc6e3debba80a7c69f2d6c51e3daa72ec8 100644 (file)
@@ -103,6 +103,22 @@ void rsnd_write(struct rsnd_priv *priv,
        regmap_fields_write(gen->regs[reg], rsnd_mod_id(mod), data);
 }
 
+void rsnd_force_write(struct rsnd_priv *priv,
+                     struct rsnd_mod *mod,
+                     enum rsnd_reg reg, u32 data)
+{
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct rsnd_gen *gen = rsnd_priv_to_gen(priv);
+
+       if (!rsnd_is_accessible_reg(priv, gen, reg))
+               return;
+
+       dev_dbg(dev, "w %s[%d] - %4d : %08x\n",
+               rsnd_mod_name(mod), rsnd_mod_id(mod), reg, data);
+
+       regmap_fields_force_write(gen->regs[reg], rsnd_mod_id(mod), data);
+}
+
 void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod,
               enum rsnd_reg reg, u32 mask, u32 data)
 {
@@ -200,12 +216,13 @@ static int rsnd_gen2_probe(struct platform_device *pdev,
                /* FIXME: it needs SSI_MODE2/3 in the future */
                RSND_GEN_M_REG(SSI_BUSIF_MODE,  0x0,    0x80),
                RSND_GEN_M_REG(SSI_BUSIF_ADINR, 0x4,    0x80),
-               RSND_GEN_M_REG(BUSIF_DALIGN,    0x8,    0x80),
+               RSND_GEN_M_REG(SSI_BUSIF_DALIGN,0x8,    0x80),
                RSND_GEN_M_REG(SSI_CTRL,        0x10,   0x80),
-               RSND_GEN_M_REG(INT_ENABLE,      0x18,   0x80),
+               RSND_GEN_M_REG(SSI_INT_ENABLE,  0x18,   0x80),
        };
        struct rsnd_regmap_field_conf conf_scu[] = {
                RSND_GEN_M_REG(SRC_BUSIF_MODE,  0x0,    0x20),
+               RSND_GEN_M_REG(SRC_BUSIF_DALIGN,0x8,    0x20),
                RSND_GEN_M_REG(SRC_ROUTE_MODE0, 0xc,    0x20),
                RSND_GEN_M_REG(SRC_CTRL,        0x10,   0x20),
                RSND_GEN_M_REG(SRC_INT_ENABLE0, 0x18,   0x20),
@@ -223,6 +240,18 @@ static int rsnd_gen2_probe(struct platform_device *pdev,
                RSND_GEN_M_REG(SRC_SRCCR,       0x224,  0x40),
                RSND_GEN_M_REG(SRC_BSDSR,       0x22c,  0x40),
                RSND_GEN_M_REG(SRC_BSISR,       0x238,  0x40),
+               RSND_GEN_M_REG(CTU_CTUIR,       0x504,  0x100),
+               RSND_GEN_M_REG(CTU_ADINR,       0x508,  0x100),
+               RSND_GEN_M_REG(MIX_SWRSR,       0xd00,  0x40),
+               RSND_GEN_M_REG(MIX_MIXIR,       0xd04,  0x40),
+               RSND_GEN_M_REG(MIX_ADINR,       0xd08,  0x40),
+               RSND_GEN_M_REG(MIX_MIXMR,       0xd10,  0x40),
+               RSND_GEN_M_REG(MIX_MVPDR,       0xd14,  0x40),
+               RSND_GEN_M_REG(MIX_MDBAR,       0xd18,  0x40),
+               RSND_GEN_M_REG(MIX_MDBBR,       0xd1c,  0x40),
+               RSND_GEN_M_REG(MIX_MDBCR,       0xd20,  0x40),
+               RSND_GEN_M_REG(MIX_MDBDR,       0xd24,  0x40),
+               RSND_GEN_M_REG(MIX_MDBER,       0xd28,  0x40),
                RSND_GEN_M_REG(DVC_SWRSR,       0xe00,  0x100),
                RSND_GEN_M_REG(DVC_DVUIR,       0xe04,  0x100),
                RSND_GEN_M_REG(DVC_ADINR,       0xe08,  0x100),
diff --git a/sound/soc/sh/rcar/mix.c b/sound/soc/sh/rcar/mix.c
new file mode 100644 (file)
index 0000000..0d5c102
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ * mix.c
+ *
+ * Copyright (c) 2015 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ *
+ * 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 "rsnd.h"
+
+#define MIX_NAME_SIZE  16
+#define MIX_NAME "mix"
+
+struct rsnd_mix {
+       struct rsnd_mix_platform_info *info; /* rcar_snd.h */
+       struct rsnd_mod mod;
+};
+
+#define rsnd_mix_nr(priv) ((priv)->mix_nr)
+#define for_each_rsnd_mix(pos, priv, i)                                        \
+       for ((i) = 0;                                                   \
+            ((i) < rsnd_mix_nr(priv)) &&                               \
+                    ((pos) = (struct rsnd_mix *)(priv)->mix + i);      \
+            i++)
+
+
+static void rsnd_mix_soft_reset(struct rsnd_mod *mod)
+{
+       rsnd_mod_write(mod, MIX_SWRSR, 0);
+       rsnd_mod_write(mod, MIX_SWRSR, 1);
+}
+
+#define rsnd_mix_initialize_lock(mod)  __rsnd_mix_initialize_lock(mod, 1)
+#define rsnd_mix_initialize_unlock(mod)        __rsnd_mix_initialize_lock(mod, 0)
+static void __rsnd_mix_initialize_lock(struct rsnd_mod *mod, u32 enable)
+{
+       rsnd_mod_write(mod, MIX_MIXIR, enable);
+}
+
+static void rsnd_mix_volume_update(struct rsnd_dai_stream *io,
+                                 struct rsnd_mod *mod)
+{
+
+       /* Disable MIX dB setting */
+       rsnd_mod_write(mod, MIX_MDBER, 0);
+
+       rsnd_mod_write(mod, MIX_MDBAR, 0);
+       rsnd_mod_write(mod, MIX_MDBBR, 0);
+       rsnd_mod_write(mod, MIX_MDBCR, 0);
+       rsnd_mod_write(mod, MIX_MDBDR, 0);
+
+       /* Enable MIX dB setting */
+       rsnd_mod_write(mod, MIX_MDBER, 1);
+}
+
+static int rsnd_mix_init(struct rsnd_mod *mod,
+                        struct rsnd_dai_stream *io,
+                        struct rsnd_priv *priv)
+{
+       rsnd_mod_hw_start(mod);
+
+       rsnd_mix_soft_reset(mod);
+
+       rsnd_mix_initialize_lock(mod);
+
+       rsnd_mod_write(mod, MIX_ADINR, rsnd_get_adinr_chan(mod, io));
+
+       rsnd_path_parse(priv, io);
+
+       /* volume step */
+       rsnd_mod_write(mod, MIX_MIXMR, 0);
+       rsnd_mod_write(mod, MIX_MVPDR, 0);
+
+       rsnd_mix_volume_update(io, mod);
+
+       rsnd_mix_initialize_unlock(mod);
+
+       return 0;
+}
+
+static int rsnd_mix_quit(struct rsnd_mod *mod,
+                        struct rsnd_dai_stream *io,
+                        struct rsnd_priv *priv)
+{
+       rsnd_mod_hw_stop(mod);
+
+       return 0;
+}
+
+static struct rsnd_mod_ops rsnd_mix_ops = {
+       .name           = MIX_NAME,
+       .init           = rsnd_mix_init,
+       .quit           = rsnd_mix_quit,
+};
+
+struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id)
+{
+       if (WARN_ON(id < 0 || id >= rsnd_mix_nr(priv)))
+               id = 0;
+
+       return &((struct rsnd_mix *)(priv->mix) + id)->mod;
+}
+
+static void rsnd_of_parse_mix(struct platform_device *pdev,
+                             const struct rsnd_of_data *of_data,
+                             struct rsnd_priv *priv)
+{
+       struct device_node *node;
+       struct rsnd_mix_platform_info *mix_info;
+       struct rcar_snd_info *info = rsnd_priv_to_info(priv);
+       struct device *dev = &pdev->dev;
+       int nr;
+
+       if (!of_data)
+               return;
+
+       node = of_get_child_by_name(dev->of_node, "rcar_sound,mix");
+       if (!node)
+               return;
+
+       nr = of_get_child_count(node);
+       if (!nr)
+               goto rsnd_of_parse_mix_end;
+
+       mix_info = devm_kzalloc(dev,
+                               sizeof(struct rsnd_mix_platform_info) * nr,
+                               GFP_KERNEL);
+       if (!mix_info) {
+               dev_err(dev, "mix info allocation error\n");
+               goto rsnd_of_parse_mix_end;
+       }
+
+       info->mix_info          = mix_info;
+       info->mix_info_nr       = nr;
+
+rsnd_of_parse_mix_end:
+       of_node_put(node);
+
+}
+
+int rsnd_mix_probe(struct platform_device *pdev,
+                  const struct rsnd_of_data *of_data,
+                  struct rsnd_priv *priv)
+{
+       struct rcar_snd_info *info = rsnd_priv_to_info(priv);
+       struct device *dev = rsnd_priv_to_dev(priv);
+       struct rsnd_mix *mix;
+       struct clk *clk;
+       char name[MIX_NAME_SIZE];
+       int i, nr, ret;
+
+       /* This driver doesn't support Gen1 at this point */
+       if (rsnd_is_gen1(priv)) {
+               dev_warn(dev, "MIX is not supported on Gen1\n");
+               return -EINVAL;
+       }
+
+       rsnd_of_parse_mix(pdev, of_data, priv);
+
+       nr = info->mix_info_nr;
+       if (!nr)
+               return 0;
+
+       mix     = devm_kzalloc(dev, sizeof(*mix) * nr, GFP_KERNEL);
+       if (!mix)
+               return -ENOMEM;
+
+       priv->mix_nr    = nr;
+       priv->mix       = mix;
+
+       for_each_rsnd_mix(mix, priv, i) {
+               snprintf(name, MIX_NAME_SIZE, "%s.%d",
+                        MIX_NAME, i);
+
+               clk = devm_clk_get(dev, name);
+               if (IS_ERR(clk))
+                       return PTR_ERR(clk);
+
+               mix->info = &info->mix_info[i];
+
+               ret = rsnd_mod_init(priv, &mix->mod, &rsnd_mix_ops,
+                                   clk, RSND_MOD_MIX, i);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+void rsnd_mix_remove(struct platform_device *pdev,
+                    struct rsnd_priv *priv)
+{
+       struct rsnd_mix *mix;
+       int i;
+
+       for_each_rsnd_mix(mix, priv, i) {
+               rsnd_mod_quit(&mix->mod);
+       }
+}
index 09fcc54a8ee067589c682df1b3b0390ea463b5ed..7a0e52b4640a5a39a0bfb3f1d496d71919e0806c 100644 (file)
@@ -47,6 +47,18 @@ enum rsnd_reg {
        RSND_REG_SCU_SYS_STATUS0,
        RSND_REG_SCU_SYS_INT_EN0,
        RSND_REG_CMD_ROUTE_SLCT,
+       RSND_REG_CTU_CTUIR,
+       RSND_REG_CTU_ADINR,
+       RSND_REG_MIX_SWRSR,
+       RSND_REG_MIX_MIXIR,
+       RSND_REG_MIX_ADINR,
+       RSND_REG_MIX_MIXMR,
+       RSND_REG_MIX_MVPDR,
+       RSND_REG_MIX_MDBAR,
+       RSND_REG_MIX_MDBBR,
+       RSND_REG_MIX_MDBCR,
+       RSND_REG_MIX_MDBDR,
+       RSND_REG_MIX_MDBER,
        RSND_REG_DVC_SWRSR,
        RSND_REG_DVC_DVUIR,
        RSND_REG_DVC_ADINR,
@@ -99,6 +111,7 @@ enum rsnd_reg {
        RSND_REG_SHARE26,
        RSND_REG_SHARE27,
        RSND_REG_SHARE28,
+       RSND_REG_SHARE29,
 
        RSND_REG_MAX,
 };
@@ -119,7 +132,7 @@ enum rsnd_reg {
 #define RSND_REG_SSI_CTRL              RSND_REG_SHARE02
 #define RSND_REG_SSI_BUSIF_MODE                RSND_REG_SHARE03
 #define RSND_REG_SSI_BUSIF_ADINR       RSND_REG_SHARE04
-#define RSND_REG_INT_ENABLE            RSND_REG_SHARE05
+#define RSND_REG_SSI_INT_ENABLE                RSND_REG_SHARE05
 #define RSND_REG_SRC_BSDSR             RSND_REG_SHARE06
 #define RSND_REG_SRC_BSISR             RSND_REG_SHARE07
 #define RSND_REG_DIV_EN                        RSND_REG_SHARE08
@@ -136,13 +149,14 @@ enum rsnd_reg {
 #define RSND_REG_AUDIO_CLK_SEL2                RSND_REG_SHARE19
 #define RSND_REG_CMD_CTRL              RSND_REG_SHARE20
 #define RSND_REG_CMDOUT_TIMSEL         RSND_REG_SHARE21
-#define RSND_REG_BUSIF_DALIGN          RSND_REG_SHARE22
+#define RSND_REG_SSI_BUSIF_DALIGN      RSND_REG_SHARE22
 #define RSND_REG_DVC_VRCTR             RSND_REG_SHARE23
 #define RSND_REG_DVC_VRPDR             RSND_REG_SHARE24
 #define RSND_REG_DVC_VRDBR             RSND_REG_SHARE25
 #define RSND_REG_SCU_SYS_STATUS1       RSND_REG_SHARE26
 #define RSND_REG_SCU_SYS_INT_EN1       RSND_REG_SHARE27
 #define RSND_REG_SRC_INT_ENABLE0       RSND_REG_SHARE28
+#define RSND_REG_SRC_BUSIF_DALIGN      RSND_REG_SHARE29
 
 struct rsnd_of_data;
 struct rsnd_priv;
@@ -157,27 +171,28 @@ struct rsnd_dai_stream;
        rsnd_read(rsnd_mod_to_priv(m), m, RSND_REG_##r)
 #define rsnd_mod_write(m, r, d) \
        rsnd_write(rsnd_mod_to_priv(m), m, RSND_REG_##r, d)
+#define rsnd_mod_force_write(m, r, d) \
+       rsnd_force_write(rsnd_mod_to_priv(m), m, RSND_REG_##r, d)
 #define rsnd_mod_bset(m, r, s, d) \
        rsnd_bset(rsnd_mod_to_priv(m), m, RSND_REG_##r, s, d)
 
 u32 rsnd_read(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg);
 void rsnd_write(struct rsnd_priv *priv, struct rsnd_mod *mod,
                enum rsnd_reg reg, u32 data);
+void rsnd_force_write(struct rsnd_priv *priv, struct rsnd_mod *mod,
+               enum rsnd_reg reg, u32 data);
 void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg,
                    u32 mask, u32 data);
-u32 rsnd_get_adinr(struct rsnd_mod *mod, struct rsnd_dai_stream *io);
+u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io);
+u32 rsnd_get_adinr_chan(struct rsnd_mod *mod, struct rsnd_dai_stream *io);
+u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io);
+void rsnd_path_parse(struct rsnd_priv *priv,
+                    struct rsnd_dai_stream *io);
 
 /*
  *     R-Car DMA
  */
 struct rsnd_dma;
-struct rsnd_dma_ops {
-       void (*start)(struct rsnd_dai_stream *io, struct rsnd_dma *dma);
-       void (*stop)(struct rsnd_dai_stream *io, struct rsnd_dma *dma);
-       int (*init)(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id,
-                   struct rsnd_mod *mod_from, struct rsnd_mod *mod_to);
-       void (*quit)(struct rsnd_dai_stream *io, struct rsnd_dma *dma);
-};
 
 struct rsnd_dmaen {
        struct dma_chan         *chan;
@@ -217,6 +232,8 @@ struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node,
  */
 enum rsnd_mod_type {
        RSND_MOD_DVC = 0,
+       RSND_MOD_MIX,
+       RSND_MOD_CTU,
        RSND_MOD_SRC,
        RSND_MOD_SSI,
        RSND_MOD_MAX,
@@ -312,7 +329,7 @@ struct rsnd_mod {
 
 #define rsnd_mod_to_priv(mod) ((mod)->priv)
 #define rsnd_mod_to_dma(mod) (&(mod)->dma)
-#define rsnd_mod_id(mod) ((mod)->id)
+#define rsnd_mod_id(mod) ((mod) ? (mod)->id : -1)
 #define rsnd_mod_hw_start(mod) clk_enable((mod)->clk)
 #define rsnd_mod_hw_stop(mod)  clk_disable((mod)->clk)
 
@@ -345,9 +362,12 @@ struct rsnd_dai_stream {
        int byte_per_period;
        int next_period_byte;
 };
-#define rsnd_io_to_mod_ssi(io) ((io)->mod[RSND_MOD_SSI])
-#define rsnd_io_to_mod_src(io) ((io)->mod[RSND_MOD_SRC])
-#define rsnd_io_to_mod_dvc(io) ((io)->mod[RSND_MOD_DVC])
+#define rsnd_io_to_mod(io, i)  ((i) < RSND_MOD_MAX ? (io)->mod[(i)] : NULL)
+#define rsnd_io_to_mod_ssi(io) rsnd_io_to_mod((io), RSND_MOD_SSI)
+#define rsnd_io_to_mod_src(io) rsnd_io_to_mod((io), RSND_MOD_SRC)
+#define rsnd_io_to_mod_ctu(io) rsnd_io_to_mod((io), RSND_MOD_CTU)
+#define rsnd_io_to_mod_mix(io) rsnd_io_to_mod((io), RSND_MOD_MIX)
+#define rsnd_io_to_mod_dvc(io) rsnd_io_to_mod((io), RSND_MOD_DVC)
 #define rsnd_io_to_rdai(io)    ((io)->rdai)
 #define rsnd_io_to_priv(io)    (rsnd_rdai_to_priv(rsnd_io_to_rdai(io)))
 #define rsnd_io_is_play(io)    (&rsnd_io_to_rdai(io)->playback == io)
@@ -436,12 +456,6 @@ struct rsnd_priv {
         */
        void *gen;
 
-       /*
-        * below value will be filled on rsnd_src_probe()
-        */
-       void *src;
-       int src_nr;
-
        /*
         * below value will be filled on rsnd_adg_probe()
         */
@@ -458,6 +472,24 @@ struct rsnd_priv {
        void *ssi;
        int ssi_nr;
 
+       /*
+        * below value will be filled on rsnd_src_probe()
+        */
+       void *src;
+       int src_nr;
+
+       /*
+        * below value will be filled on rsnd_ctu_probe()
+        */
+       void *ctu;
+       int ctu_nr;
+
+       /*
+        * below value will be filled on rsnd_mix_probe()
+        */
+       void *mix;
+       int mix_nr;
+
        /*
         * below value will be filled on rsnd_dvc_probe()
         */
@@ -530,6 +562,19 @@ int rsnd_kctrl_new_e(struct rsnd_mod *mod,
                     const char * const *texts,
                     u32 max);
 
+/*
+ *     R-Car SSI
+ */
+int rsnd_ssi_probe(struct platform_device *pdev,
+                  const struct rsnd_of_data *of_data,
+                  struct rsnd_priv *priv);
+void rsnd_ssi_remove(struct platform_device *pdev,
+                    struct rsnd_priv *priv);
+struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id);
+int rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod);
+int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod);
+int rsnd_ssi_use_busif(struct rsnd_dai_stream *io, struct rsnd_mod *mod);
+
 /*
  *     R-Car SRC
  */
@@ -550,20 +595,27 @@ int rsnd_src_ssiu_stop(struct rsnd_mod *ssi_mod,
 int rsnd_src_ssi_irq_enable(struct rsnd_mod *ssi_mod);
 int rsnd_src_ssi_irq_disable(struct rsnd_mod *ssi_mod);
 
-#define rsnd_src_nr(priv) ((priv)->src_nr)
+/*
+ *     R-Car CTU
+ */
+int rsnd_ctu_probe(struct platform_device *pdev,
+                  const struct rsnd_of_data *of_data,
+                  struct rsnd_priv *priv);
+
+void rsnd_ctu_remove(struct platform_device *pdev,
+                    struct rsnd_priv *priv);
+struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id);
 
 /*
- *     R-Car SSI
+ *     R-Car MIX
  */
-int rsnd_ssi_probe(struct platform_device *pdev,
+int rsnd_mix_probe(struct platform_device *pdev,
                   const struct rsnd_of_data *of_data,
                   struct rsnd_priv *priv);
-void rsnd_ssi_remove(struct platform_device *pdev,
+
+void rsnd_mix_remove(struct platform_device *pdev,
                     struct rsnd_priv *priv);
-struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id);
-int rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod);
-int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod);
-int rsnd_ssi_use_busif(struct rsnd_dai_stream *io, struct rsnd_mod *mod);
+struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id);
 
 /*
  *     R-Car DVC
@@ -575,7 +627,4 @@ void rsnd_dvc_remove(struct platform_device *pdev,
                     struct rsnd_priv *priv);
 struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id);
 
-#define rsnd_dvc_nr(priv) ((priv)->dvc_nr)
-
-
 #endif
index 84e935711e29e4424d560b3381b6357af6b84c00..d61db9c385eafd3bc6fca47edad10bff696b3ba2 100644 (file)
@@ -41,6 +41,7 @@ static const struct rsrc_card_of_data routes_of_ssi0_ak4642 = {
 static const struct of_device_id rsrc_card_of_match[] = {
        { .compatible = "renesas,rsrc-card,lager",      .data = &routes_of_ssi0_ak4642 },
        { .compatible = "renesas,rsrc-card,koelsch",    .data = &routes_of_ssi0_ak4642 },
+       { .compatible = "renesas,rsrc-card", },
        {},
 };
 MODULE_DEVICE_TABLE(of, rsrc_card_of_match);
@@ -242,8 +243,15 @@ static int rsrc_card_parse_links(struct device_node *np,
                snd_soc_of_get_dai_name(np, &dai_link->codec_dai_name);
 
                /* additional name prefix */
-               priv->codec_conf.of_node        = dai_link->codec_of_node;
-               priv->codec_conf.name_prefix    = of_data->prefix;
+               if (of_data) {
+                       priv->codec_conf.of_node = dai_link->codec_of_node;
+                       priv->codec_conf.name_prefix = of_data->prefix;
+               } else {
+                       snd_soc_of_parse_audio_prefix(&priv->snd_card,
+                                                     &priv->codec_conf,
+                                                     dai_link->codec_of_node,
+                                                     "audio-prefix");
+               }
 
                /* set dai_name */
                snprintf(dai_props->dai_name, DAI_NAME_NUM, "be.%s",
@@ -361,8 +369,14 @@ static int rsrc_card_parse_of(struct device_node *node,
        priv->snd_card.num_links                = num;
        priv->snd_card.codec_conf               = &priv->codec_conf;
        priv->snd_card.num_configs              = 1;
-       priv->snd_card.of_dapm_routes           = of_data->routes;
-       priv->snd_card.num_of_dapm_routes       = of_data->num_routes;
+
+       if (of_data) {
+               priv->snd_card.of_dapm_routes           = of_data->routes;
+               priv->snd_card.num_of_dapm_routes       = of_data->num_routes;
+       } else {
+               snd_soc_of_parse_audio_routing(&priv->snd_card,
+                                              "audio-routing");
+       }
 
        /* Parse the card name from DT */
        snd_soc_of_parse_card_name(&priv->snd_card, "card-name");
index c61c171801423fc03b98598a3fd1624c7eb4155c..89a18e102feb100b57350024a3d548261e91243e 100644 (file)
@@ -30,6 +30,7 @@ struct rsnd_src {
 
 #define RSND_SRC_NAME_SIZE 16
 
+#define rsnd_src_nr(priv) ((priv)->src_nr)
 #define rsnd_enable_sync_convert(src) ((src)->sen.val)
 #define rsnd_src_of_node(priv) \
        of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,src")
@@ -117,6 +118,20 @@ struct rsnd_src {
 /*
  *             Gen1/Gen2 common functions
  */
+static void rsnd_src_soft_reset(struct rsnd_mod *mod)
+{
+       rsnd_mod_write(mod, SRC_SWRSR, 0);
+       rsnd_mod_write(mod, SRC_SWRSR, 1);
+}
+
+
+#define rsnd_src_initialize_lock(mod)  __rsnd_src_initialize_lock(mod, 1)
+#define rsnd_src_initialize_unlock(mod)        __rsnd_src_initialize_lock(mod, 0)
+static void __rsnd_src_initialize_lock(struct rsnd_mod *mod, u32 enable)
+{
+       rsnd_mod_write(mod, SRC_SRCIR, enable);
+}
+
 static struct dma_chan *rsnd_src_dma_req(struct rsnd_dai_stream *io,
                                         struct rsnd_mod *mod)
 {
@@ -133,7 +148,6 @@ int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod,
                        int use_busif)
 {
        struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
-       struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
        int ssi_id = rsnd_mod_id(ssi_mod);
 
        /*
@@ -170,27 +184,14 @@ int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod,
         * DMA settings for SSIU
         */
        if (use_busif) {
-               u32 val = 0x76543210;
-               u32 mask = ~0;
+               u32 val = rsnd_get_dalign(ssi_mod, io);
 
                rsnd_mod_write(ssi_mod, SSI_BUSIF_ADINR,
-                              rsnd_get_adinr(ssi_mod, io));
+                              rsnd_get_adinr_bit(ssi_mod, io));
                rsnd_mod_write(ssi_mod, SSI_BUSIF_MODE,  1);
                rsnd_mod_write(ssi_mod, SSI_CTRL, 0x1);
 
-               mask <<= runtime->channels * 4;
-               val = val & mask;
-
-               switch (runtime->sample_bits) {
-               case 16:
-                       val |= 0x67452301 & ~mask;
-                       break;
-               case 32:
-                       val |= 0x76543210 & ~mask;
-                       break;
-               }
-               rsnd_mod_write(ssi_mod, BUSIF_DALIGN, val);
-
+               rsnd_mod_write(ssi_mod, SSI_BUSIF_DALIGN, val);
        }
 
        return 0;
@@ -215,10 +216,9 @@ int rsnd_src_ssi_irq_enable(struct rsnd_mod *ssi_mod)
                return 0;
 
        /* enable SSI interrupt if Gen2 */
-       if (rsnd_ssi_is_dma_mode(ssi_mod))
-               rsnd_mod_write(ssi_mod, INT_ENABLE, 0x0e000000);
-       else
-               rsnd_mod_write(ssi_mod, INT_ENABLE, 0x0f000000);
+       rsnd_mod_write(ssi_mod, SSI_INT_ENABLE,
+                      rsnd_ssi_is_dma_mode(ssi_mod) ?
+                      0x0e000000 : 0x0f000000);
 
        return 0;
 }
@@ -231,7 +231,7 @@ int rsnd_src_ssi_irq_disable(struct rsnd_mod *ssi_mod)
                return 0;
 
        /* disable SSI interrupt if Gen2 */
-       rsnd_mod_write(ssi_mod, INT_ENABLE, 0x00000000);
+       rsnd_mod_write(ssi_mod, SSI_INT_ENABLE, 0x00000000);
 
        return 0;
 }
@@ -294,12 +294,8 @@ static int rsnd_src_set_convert_rate(struct rsnd_mod *mod,
        if (convert_rate)
                fsrate = 0x0400000 / convert_rate * runtime->rate;
 
-       /* set/clear soft reset */
-       rsnd_mod_write(mod, SRC_SWRSR, 0);
-       rsnd_mod_write(mod, SRC_SWRSR, 1);
-
        /* Set channel number and output bit length */
-       rsnd_mod_write(mod, SRC_ADINR, rsnd_get_adinr(mod, io));
+       rsnd_mod_write(mod, SRC_ADINR, rsnd_get_adinr_bit(mod, io));
 
        /* Enable the initial value of IFS */
        if (fsrate) {
@@ -358,17 +354,15 @@ static int rsnd_src_init(struct rsnd_mod *mod,
 
        rsnd_mod_hw_start(mod);
 
+       rsnd_src_soft_reset(mod);
+
+       rsnd_src_initialize_lock(mod);
+
        src->err = 0;
 
        /* reset sync convert_rate */
        src->sync.val = 0;
 
-       /*
-        * Initialize the operation of the SRC internal circuits
-        * see rsnd_src_start()
-        */
-       rsnd_mod_write(mod, SRC_SRCIR, 1);
-
        return 0;
 }
 
@@ -395,11 +389,7 @@ static int rsnd_src_quit(struct rsnd_mod *mod,
 
 static int rsnd_src_start(struct rsnd_mod *mod)
 {
-       /*
-        * Cancel the initialization and operate the SRC function
-        * see rsnd_src_init()
-        */
-       rsnd_mod_write(mod, SRC_SRCIR, 0);
+       rsnd_src_initialize_unlock(mod);
 
        return 0;
 }
@@ -617,6 +607,14 @@ static void rsnd_src_irq_ctrol_gen2(struct rsnd_mod *mod, int enable)
                int_val = 0;
        }
 
+       /*
+        * WORKAROUND
+        *
+        * ignore over flow error when rsnd_enable_sync_convert()
+        */
+       if (rsnd_enable_sync_convert(src))
+               sys_int_val = sys_int_val & 0xffff;
+
        rsnd_mod_write(mod, SRC_INT_ENABLE0, int_val);
        rsnd_mod_bset(mod, SCU_SYS_INT_EN0, sys_int_mask, sys_int_val);
        rsnd_mod_bset(mod, SCU_SYS_INT_EN1, sys_int_mask, sys_int_val);
@@ -632,11 +630,22 @@ static void rsnd_src_error_clear_gen2(struct rsnd_mod *mod)
 
 static bool rsnd_src_error_record_gen2(struct rsnd_mod *mod)
 {
-       u32 val = OUF_SRC(rsnd_mod_id(mod));
+       struct rsnd_src *src = rsnd_mod_to_src(mod);
+       u32 val0, val1;
        bool ret = false;
 
-       if ((rsnd_mod_read(mod, SCU_SYS_STATUS0) & val) ||
-           (rsnd_mod_read(mod, SCU_SYS_STATUS1) & val)) {
+       val0 = val1 = OUF_SRC(rsnd_mod_id(mod));
+
+       /*
+        * WORKAROUND
+        *
+        * ignore over flow error when rsnd_enable_sync_convert()
+        */
+       if (rsnd_enable_sync_convert(src))
+               val0 = val0 & 0xffff;
+
+       if ((rsnd_mod_read(mod, SCU_SYS_STATUS0) & val0) ||
+           (rsnd_mod_read(mod, SCU_SYS_STATUS1) & val1)) {
                struct rsnd_src *src = rsnd_mod_to_src(mod);
 
                src->err++;
@@ -652,7 +661,20 @@ static bool rsnd_src_error_record_gen2(struct rsnd_mod *mod)
 static int _rsnd_src_start_gen2(struct rsnd_mod *mod,
                                struct rsnd_dai_stream *io)
 {
-       u32 val = rsnd_io_to_mod_dvc(io) ? 0x01 : 0x11;
+       struct rsnd_src *src = rsnd_mod_to_src(mod);
+       u32 val;
+
+       val = rsnd_get_dalign(mod, io);
+
+       rsnd_mod_write(mod, SRC_BUSIF_DALIGN, val);
+
+       /*
+        * WORKAROUND
+        *
+        * Enable SRC output if you want to use sync convert together with DVC
+        */
+       val = (rsnd_io_to_mod_dvc(io) && !rsnd_enable_sync_convert(src)) ?
+               0x01 : 0x11;
 
        rsnd_mod_write(mod, SRC_CTRL, val);
 
@@ -921,13 +943,6 @@ static int rsnd_src_pcm_new(struct rsnd_mod *mod,
        if (!rsnd_rdai_is_clk_master(rdai))
                return 0;
 
-       /*
-        * We can't use SRC sync convert
-        * if it has DVC
-        */
-       if (rsnd_io_to_mod_dvc(io))
-               return 0;
-
        /*
         * enable sync convert
         */
@@ -1047,10 +1062,8 @@ int rsnd_src_probe(struct platform_device *pdev,
                return 0;
 
        src     = devm_kzalloc(dev, sizeof(*src) * nr, GFP_KERNEL);
-       if (!src) {
-               dev_err(dev, "SRC allocate failed\n");
+       if (!src)
                return -ENOMEM;
-       }
 
        priv->src_nr    = nr;
        priv->src       = src;
index 2fbe59f7f9b5a845f5b97376de05bad6ff9c162f..d45b9a7e324efb49a5159417232c9f43815ebfed 100644 (file)
@@ -770,10 +770,8 @@ int rsnd_ssi_probe(struct platform_device *pdev,
         */
        nr      = info->ssi_info_nr;
        ssi     = devm_kzalloc(dev, sizeof(*ssi) * nr, GFP_KERNEL);
-       if (!ssi) {
-               dev_err(dev, "SSI allocate failed\n");
+       if (!ssi)
                return -ENOMEM;
-       }
 
        priv->ssi       = ssi;
        priv->ssi_nr    = nr;