Merge remote-tracking branches 'asoc/topic/rcar', 'asoc/topic/reg-default', 'asoc/topic/rl6231', 'asoc/topic/rockchip' and 'asoc/topic/rt286' into asoc-next

This commit is contained in:
Mark Brown 2015-08-30 15:55:54 +01:00
46 changed files with 1142 additions and 304 deletions

View 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>;

View 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:

View 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 */

View 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));

View 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 },

View 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 },

View 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 },
};

View 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 },

View 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 },

View 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

View 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) {

View 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 },

View 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;

View 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 },

View 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)

View 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;

View 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 },

View 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 },

View 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 },

View 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 },

View File

@ -11,38 +11,98 @@
*/
#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;
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;
}
if (rate < 1000000 * div[0]) {
pr_warn("Base clock rate %d is too low\n", rate);
return -EINVAL;
}
return idx;
for (i = 0; i < ARRAY_SIZE(div); i++) {
/* find divider that gives DMIC frequency below 3MHz */
if (3000000 * div[i] >= rate)
return i;
}
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;

View 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__ */

View 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;
}

View 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

View 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

View 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

View 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

View 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

View 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 },

View 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 },

View 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 },

View 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 },

View 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 },

View 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,
},

View 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,
},

View 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

View 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.
*/
/* SRC */
ret = rsnd_path_parse(priv, io, src);
/* SSI */
ret = rsnd_path_add(priv, io, ssi);
if (ret < 0)
return ret;
/* SSI */
ret = rsnd_path_parse(priv, io, ssi);
/* SRC */
ret = rsnd_path_add(priv, io, src);
if (ret < 0)
return ret;
/* 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;

171
sound/soc/sh/rcar/ctu.c Normal file
View File

@ -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);
}
}

View 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;
/*
* in play case...
*
* src -> dst
*
* mem -> SSI
* mem -> SRC -> SSI
* mem -> SRC -> DVC -> SSI
*/
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[i] = (is_play) ? src : dvc;
i++;
mod[i] = (is_play) ? dvc : src;
src = NULL;
dvc = NULL;
}
if (mod[i] == this)
index = i;
if (mod[i] == ssi)
break;
nr += !!rsnd_io_to_mod(io, i);
}
if (is_play) {
*mod_from = mod[index - 1];
*mod_to = mod[index];
/*
* [S] -*-> [E]
* [S] -*-> SRC -o-> [E]
* [S] -*-> SRC -> DVC -o-> [E]
* [S] -*-> SRC -> CTU -> MIX -> DVC -o-> [E]
*
* playback [S] = mem
* [E] = SSI
*
* capture [S] = SSI
* [E] = mem
*
* -*-> Audio DMAC
* -o-> Audio DMAC peri peri
*/
mod_start = (is_play) ? NULL : ssi;
mod_end = (is_play) ? ssi : NULL;
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;
}
}
mod[i] = mod_end;
/*
* | 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);
}

View 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
};
rsnd_mod_hw_start(mod);
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_dvc_soft_reset(mod);
rsnd_mod_hw_start(dvc_mod);
rsnd_dvc_initialize_lock(mod);
/*
* fixme
* it doesn't support CTU/MIX
*/
rsnd_mod_write(dvc_mod, CMD_ROUTE_SLCT, route[src_id]);
rsnd_path_parse(priv, io);
rsnd_mod_write(dvc_mod, DVC_SWRSR, 0);
rsnd_mod_write(dvc_mod, DVC_SWRSR, 1);
rsnd_mod_write(dvc_mod, DVC_DVUIR, 1);
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;

View 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),

200
sound/soc/sh/rcar/mix.c Normal file
View File

@ -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);
}
}

View 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 SSI
* R-Car CTU
*/
int rsnd_ssi_probe(struct platform_device *pdev,
int rsnd_ctu_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_ctu_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_ctu_mod_get(struct rsnd_priv *priv, int id);
/*
* R-Car MIX
*/
int rsnd_mix_probe(struct platform_device *pdev,
const struct rsnd_of_data *of_data,
struct rsnd_priv *priv);
void rsnd_mix_remove(struct platform_device *pdev,
struct rsnd_priv *priv);
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

View 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");

View 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;

View 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;