diff options
Diffstat (limited to 'sound/soc/sh/rcar/ssi.c')
-rw-r--r-- | sound/soc/sh/rcar/ssi.c | 270 |
1 files changed, 95 insertions, 175 deletions
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index d0ded427a836..0a46aa1975fa 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -11,12 +11,14 @@ /* * you can enable below define if you don't need * SSI interrupt status debug message when debugging - * see rsnd_dbg_irq_status() + * see rsnd_print_irq_status() * * #define RSND_DEBUG_NO_IRQ_STATUS 1 */ #include <sound/simple_card_utils.h> +#include <linux/of.h> +#include <linux/of_irq.h> #include <linux/delay.h> #include "rsnd.h" #define RSND_SSI_NAME_SIZE 16 @@ -24,23 +26,23 @@ /* * SSICR */ -#define FORCE (1 << 31) /* Fixed */ -#define DMEN (1 << 28) /* DMA Enable */ -#define UIEN (1 << 27) /* Underflow Interrupt Enable */ -#define OIEN (1 << 26) /* Overflow Interrupt Enable */ -#define IIEN (1 << 25) /* Idle Mode Interrupt Enable */ -#define DIEN (1 << 24) /* Data Interrupt Enable */ -#define CHNL_4 (1 << 22) /* Channels */ -#define CHNL_6 (2 << 22) /* Channels */ -#define CHNL_8 (3 << 22) /* Channels */ -#define DWL_MASK (7 << 19) /* Data Word Length mask */ -#define DWL_8 (0 << 19) /* Data Word Length */ -#define DWL_16 (1 << 19) /* Data Word Length */ -#define DWL_18 (2 << 19) /* Data Word Length */ -#define DWL_20 (3 << 19) /* Data Word Length */ -#define DWL_22 (4 << 19) /* Data Word Length */ -#define DWL_24 (5 << 19) /* Data Word Length */ -#define DWL_32 (6 << 19) /* Data Word Length */ +#define FORCE (1u << 31) /* Fixed */ +#define DMEN (1u << 28) /* DMA Enable */ +#define UIEN (1u << 27) /* Underflow Interrupt Enable */ +#define OIEN (1u << 26) /* Overflow Interrupt Enable */ +#define IIEN (1u << 25) /* Idle Mode Interrupt Enable */ +#define DIEN (1u << 24) /* Data Interrupt Enable */ +#define CHNL_4 (1u << 22) /* Channels */ +#define CHNL_6 (2u << 22) /* Channels */ +#define CHNL_8 (3u << 22) /* Channels */ +#define DWL_MASK (7u << 19) /* Data Word Length mask */ +#define DWL_8 (0u << 19) /* Data Word Length */ +#define DWL_16 (1u << 19) /* Data Word Length */ +#define DWL_18 (2u << 19) /* Data Word Length */ +#define DWL_20 (3u << 19) /* Data Word Length */ +#define DWL_22 (4u << 19) /* Data Word Length */ +#define DWL_24 (5u << 19) /* Data Word Length */ +#define DWL_32 (6u << 19) /* Data Word Length */ /* * System word length @@ -117,8 +119,6 @@ struct rsnd_ssi { (rsnd_ssi_run_mods(io) & (1 << rsnd_mod_id(mod))) #define rsnd_ssi_can_output_clk(mod) (!__rsnd_ssi_is_pin_sharing(mod)) -static int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod); - int rsnd_ssi_use_busif(struct rsnd_dai_stream *io) { struct rsnd_mod *mod = rsnd_io_to_mod_ssi(io); @@ -167,8 +167,7 @@ static void rsnd_ssi_status_check(struct rsnd_mod *mod, static u32 rsnd_ssi_multi_secondaries(struct rsnd_dai_stream *io) { - struct rsnd_mod *mod; - enum rsnd_mod_type types[] = { + static const enum rsnd_mod_type types[] = { RSND_MOD_SSIM1, RSND_MOD_SSIM2, RSND_MOD_SSIM3, @@ -177,7 +176,8 @@ static u32 rsnd_ssi_multi_secondaries(struct rsnd_dai_stream *io) mask = 0; for (i = 0; i < ARRAY_SIZE(types); i++) { - mod = rsnd_io_to_mod(io, types[i]); + struct rsnd_mod *mod = rsnd_io_to_mod(io, types[i]); + if (!mod) continue; @@ -230,7 +230,7 @@ unsigned int rsnd_ssi_clk_query(struct rsnd_dai *rdai, int param1, int param2, int *idx) { struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); - int ssi_clk_mul_table[] = { + static const int ssi_clk_mul_table[] = { 1, 2, 4, 8, 16, 6, 12, }; int j, ret; @@ -305,15 +305,14 @@ static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod, return 0; } + ret = -EIO; main_rate = rsnd_ssi_clk_query(rdai, rate, chan, &idx); - if (!main_rate) { - dev_err(dev, "unsupported clock rate\n"); - return -EIO; - } + if (!main_rate) + goto rate_err; ret = rsnd_adg_ssi_clk_try_start(mod, main_rate); if (ret < 0) - return ret; + goto rate_err; /* * SSI clock will be output contiguously @@ -335,6 +334,10 @@ static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod, rsnd_mod_name(mod), chan, rate); return 0; + +rate_err: + dev_err(dev, "unsupported clock rate\n"); + return ret; } static void rsnd_ssi_master_clk_stop(struct rsnd_mod *mod, @@ -372,9 +375,6 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod, u32 wsr = ssi->wsr; int width; int is_tdm, is_tdm_split; - int id = rsnd_mod_id(mod); - int i; - u32 sys_int_enable = 0; is_tdm = rsnd_runtime_is_tdm(io); is_tdm_split = rsnd_runtime_is_tdm_split(io); @@ -400,7 +400,6 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod, * see * rsnd_ssiu_init_gen2() */ - wsr = ssi->wsr; if (is_tdm || is_tdm_split) { wsr |= WS_MODE; cr_own |= CHNL_8; @@ -450,38 +449,6 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod, cr_mode = DIEN; /* PIO : enable Data interrupt */ } - /* enable busif buffer over/under run interrupt. */ - if (is_tdm || is_tdm_split) { - switch (id) { - case 0: - case 1: - case 2: - case 3: - case 4: - for (i = 0; i < 4; i++) { - sys_int_enable = rsnd_mod_read(mod, - SSI_SYS_INT_ENABLE(i * 2)); - sys_int_enable |= 0xf << (id * 4); - rsnd_mod_write(mod, - SSI_SYS_INT_ENABLE(i * 2), - sys_int_enable); - } - - break; - case 9: - for (i = 0; i < 4; i++) { - sys_int_enable = rsnd_mod_read(mod, - SSI_SYS_INT_ENABLE((i * 2) + 1)); - sys_int_enable |= 0xf << 4; - rsnd_mod_write(mod, - SSI_SYS_INT_ENABLE((i * 2) + 1), - sys_int_enable); - } - - break; - } - } - init_end: ssi->cr_own = cr_own; ssi->cr_mode = cr_mode; @@ -507,13 +474,20 @@ static int rsnd_ssi_init(struct rsnd_mod *mod, struct rsnd_priv *priv) { struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); + int ret; if (!rsnd_ssi_is_run_mods(mod, io)) return 0; + ret = rsnd_ssi_master_clk_start(mod, io); + if (ret < 0) + return ret; + ssi->usrcnt++; - rsnd_mod_power_on(mod); + ret = rsnd_mod_power_on(mod); + if (ret < 0) + return ret; rsnd_ssi_config_init(mod, io); @@ -531,13 +505,6 @@ static int rsnd_ssi_quit(struct rsnd_mod *mod, { struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); struct device *dev = rsnd_priv_to_dev(priv); - int is_tdm, is_tdm_split; - int id = rsnd_mod_id(mod); - int i; - u32 sys_int_enable = 0; - - is_tdm = rsnd_runtime_is_tdm(io); - is_tdm_split = rsnd_runtime_is_tdm_split(io); if (!rsnd_ssi_is_run_mods(mod, io)) return 0; @@ -559,38 +526,6 @@ static int rsnd_ssi_quit(struct rsnd_mod *mod, ssi->wsr = 0; } - /* disable busif buffer over/under run interrupt. */ - if (is_tdm || is_tdm_split) { - switch (id) { - case 0: - case 1: - case 2: - case 3: - case 4: - for (i = 0; i < 4; i++) { - sys_int_enable = rsnd_mod_read(mod, - SSI_SYS_INT_ENABLE(i * 2)); - sys_int_enable &= ~(0xf << (id * 4)); - rsnd_mod_write(mod, - SSI_SYS_INT_ENABLE(i * 2), - sys_int_enable); - } - - break; - case 9: - for (i = 0; i < 4; i++) { - sys_int_enable = rsnd_mod_read(mod, - SSI_SYS_INT_ENABLE((i * 2) + 1)); - sys_int_enable &= ~(0xf << 4); - rsnd_mod_write(mod, - SSI_SYS_INT_ENABLE((i * 2) + 1), - sys_int_enable); - } - - break; - } - } - return 0; } @@ -743,12 +678,6 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod, u32 status; bool elapsed = false; bool stop = false; - int id = rsnd_mod_id(mod); - int i; - int is_tdm, is_tdm_split; - - is_tdm = rsnd_runtime_is_tdm(io); - is_tdm_split = rsnd_runtime_is_tdm_split(io); spin_lock(&priv->lock); @@ -764,58 +693,13 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod, /* DMA only */ if (is_dma && (status & (UIRQ | OIRQ))) { - rsnd_dbg_irq_status(dev, "%s err status : 0x%08x\n", - rsnd_mod_name(mod), status); + rsnd_print_irq_status(dev, "%s err status : 0x%08x\n", + rsnd_mod_name(mod), status); stop = true; } - status = 0; - - if (is_tdm || is_tdm_split) { - switch (id) { - case 0: - case 1: - case 2: - case 3: - case 4: - for (i = 0; i < 4; i++) { - status = rsnd_mod_read(mod, - SSI_SYS_STATUS(i * 2)); - status &= 0xf << (id * 4); - - if (status) { - rsnd_dbg_irq_status(dev, - "%s err status : 0x%08x\n", - rsnd_mod_name(mod), status); - rsnd_mod_write(mod, - SSI_SYS_STATUS(i * 2), - 0xf << (id * 4)); - stop = true; - break; - } - } - break; - case 9: - for (i = 0; i < 4; i++) { - status = rsnd_mod_read(mod, - SSI_SYS_STATUS((i * 2) + 1)); - status &= 0xf << 4; - - if (status) { - rsnd_dbg_irq_status(dev, - "%s err status : 0x%08x\n", - rsnd_mod_name(mod), status); - rsnd_mod_write(mod, - SSI_SYS_STATUS((i * 2) + 1), - 0xf << 4); - stop = true; - break; - } - } - break; - } - } + stop |= rsnd_ssiu_busif_err_status_clear(mod); rsnd_ssi_status_clear(mod); rsnd_ssi_interrupt_out: @@ -1060,13 +944,6 @@ static int rsnd_ssi_pio_pointer(struct rsnd_mod *mod, return 0; } -static int rsnd_ssi_prepare(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - return rsnd_ssi_master_clk_start(mod, io); -} - static struct rsnd_mod_ops rsnd_ssi_pio_ops = { .name = SSI_NAME, .probe = rsnd_ssi_common_probe, @@ -1079,7 +956,6 @@ static struct rsnd_mod_ops rsnd_ssi_pio_ops = { .pointer = rsnd_ssi_pio_pointer, .pcm_new = rsnd_ssi_pcm_new, .hw_params = rsnd_ssi_hw_params, - .prepare = rsnd_ssi_prepare, .get_status = rsnd_ssi_get_status, }; @@ -1150,8 +1026,36 @@ static struct dma_chan *rsnd_ssi_dma_req(struct rsnd_dai_stream *io, name = is_play ? "rx" : "tx"; return rsnd_dma_request_channel(rsnd_ssi_of_node(priv), - mod, name); + SSI_NAME, mod, name); +} + +#ifdef CONFIG_DEBUG_FS +static void rsnd_ssi_debug_info(struct seq_file *m, + struct rsnd_dai_stream *io, + struct rsnd_mod *mod) +{ + struct rsnd_dai *rdai = rsnd_io_to_rdai(io); + struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); + + seq_printf(m, "clock: %s\n", rsnd_rdai_is_clk_master(rdai) ? + "provider" : "consumer"); + seq_printf(m, "bit_clk_inv: %d\n", rdai->bit_clk_inv); + seq_printf(m, "frm_clk_inv: %d\n", rdai->frm_clk_inv); + seq_printf(m, "pin share: %d\n", __rsnd_ssi_is_pin_sharing(mod)); + seq_printf(m, "can out clk: %d\n", rsnd_ssi_can_output_clk(mod)); + seq_printf(m, "multi secondary: %d\n", rsnd_ssi_is_multi_secondary(mod, io)); + seq_printf(m, "tdm: %d, %d\n", rsnd_runtime_is_tdm(io), + rsnd_runtime_is_tdm_split(io)); + seq_printf(m, "chan: %d\n", ssi->chan); + seq_printf(m, "user: %d\n", ssi->usrcnt); + + rsnd_debugfs_mod_reg_show(m, mod, RSND_GEN2_SSI, + rsnd_mod_id(mod) * 0x40, 0x40); } +#define DEBUG_INFO .debug_info = rsnd_ssi_debug_info +#else +#define DEBUG_INFO +#endif static struct rsnd_mod_ops rsnd_ssi_dma_ops = { .name = SSI_NAME, @@ -1166,11 +1070,11 @@ static struct rsnd_mod_ops rsnd_ssi_dma_ops = { .pcm_new = rsnd_ssi_pcm_new, .fallback = rsnd_ssi_fallback, .hw_params = rsnd_ssi_hw_params, - .prepare = rsnd_ssi_prepare, .get_status = rsnd_ssi_get_status, + DEBUG_INFO }; -static int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod) +int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod) { return mod->ops == &rsnd_ssi_dma_ops; } @@ -1182,7 +1086,7 @@ static void rsnd_ssi_connect(struct rsnd_mod *mod, struct rsnd_dai_stream *io) { struct rsnd_dai *rdai = rsnd_io_to_rdai(io); - enum rsnd_mod_type types[] = { + static const enum rsnd_mod_type types[] = { RSND_MOD_SSI, RSND_MOD_SSIM1, RSND_MOD_SSIM2, @@ -1208,9 +1112,9 @@ void rsnd_parse_connect_ssi(struct rsnd_dai *rdai, struct device_node *capture) { struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); + struct device *dev = rsnd_priv_to_dev(priv); struct device_node *node; struct device_node *np; - struct rsnd_mod *mod; int i; node = rsnd_ssi_of_node(priv); @@ -1219,7 +1123,16 @@ void rsnd_parse_connect_ssi(struct rsnd_dai *rdai, i = 0; for_each_child_of_node(node, np) { + struct rsnd_mod *mod; + + i = rsnd_node_fixed_index(dev, np, SSI_NAME, i); + if (i < 0) { + of_node_put(np); + break; + } + mod = rsnd_ssi_mod_get(priv, i); + if (np == playback) rsnd_ssi_connect(mod, &rdai->playback); if (np == capture) @@ -1261,7 +1174,7 @@ int rsnd_ssi_probe(struct rsnd_priv *priv) if (!node) return -EINVAL; - nr = of_get_child_count(node); + nr = rsnd_node_count(priv, node, SSI_NAME); if (!nr) { ret = -EINVAL; goto rsnd_ssi_probe_done; @@ -1281,6 +1194,13 @@ int rsnd_ssi_probe(struct rsnd_priv *priv) if (!of_device_is_available(np)) goto skip; + i = rsnd_node_fixed_index(dev, np, SSI_NAME, i); + if (i < 0) { + ret = -EINVAL; + of_node_put(np); + goto rsnd_ssi_probe_done; + } + ssi = rsnd_ssi_get(priv, i); snprintf(name, RSND_SSI_NAME_SIZE, "%s.%d", @@ -1293,10 +1213,10 @@ int rsnd_ssi_probe(struct rsnd_priv *priv) goto rsnd_ssi_probe_done; } - if (of_get_property(np, "shared-pin", NULL)) + if (of_property_read_bool(np, "shared-pin")) rsnd_flags_set(ssi, RSND_SSI_CLK_PIN_SHARE); - if (of_get_property(np, "no-busif", NULL)) + if (of_property_read_bool(np, "no-busif")) rsnd_flags_set(ssi, RSND_SSI_NO_BUSIF); ssi->irq = irq_of_parse_and_map(np, 0); |