diff --git a/asoc/codecs/bolero/bolero_cdc.c b/asoc/codecs/bolero/bolero_cdc.c index 479b71c949db..ab78ce869d6c 100644 --- a/asoc/codecs/bolero/bolero_cdc.c +++ b/asoc/codecs/bolero/bolero_cdc.c @@ -24,6 +24,14 @@ static struct snd_soc_codec_driver bolero; +/* MCLK_MUX table for all macros */ +static u16 bolero_mclk_mux_tbl[MAX_MACRO][MCLK_MUX_MAX] = { + {TX_MACRO, VA_MACRO}, + {TX_MACRO, RX_MACRO}, + {TX_MACRO, WSA_MACRO}, + {TX_MACRO, VA_MACRO}, +}; + static void bolero_ahb_write_device(char __iomem *io_base, u16 reg, u8 value) { @@ -45,24 +53,31 @@ static int __bolero_reg_read(struct bolero_priv *priv, u16 macro_id, u16 reg, u8 *val) { int ret = -EINVAL; + u16 current_mclk_mux_macro; - if (!priv->macro_params[macro_id].mclk_fn) { + mutex_lock(&priv->clk_lock); + current_mclk_mux_macro = + priv->current_mclk_mux_macro[macro_id]; + if (!priv->macro_params[current_mclk_mux_macro].mclk_fn) { dev_dbg_ratelimited(priv->dev, - "%s: mclk_fn not init for macro-id-%d\n", - __func__, macro_id); - return ret; + "%s: mclk_fn not init for macro-id:%d, current_mclk_mux_macro:%d\n", + __func__, macro_id, current_mclk_mux_macro); + goto err; } - ret = priv->macro_params[macro_id].mclk_fn( - priv->macro_params[macro_id].dev, true); + ret = priv->macro_params[current_mclk_mux_macro].mclk_fn( + priv->macro_params[current_mclk_mux_macro].dev, true); if (ret) { dev_dbg_ratelimited(priv->dev, - "%s: clock enable failed\n", __func__); - return ret; + "%s: clock enable failed for macro-id:%d, current_mclk_mux_macro:%d\n", + __func__, macro_id, current_mclk_mux_macro); + goto err; } bolero_ahb_read_device( priv->macro_params[macro_id].io_base, reg, val); - priv->macro_params[macro_id].mclk_fn( - priv->macro_params[macro_id].dev, false); + priv->macro_params[current_mclk_mux_macro].mclk_fn( + priv->macro_params[current_mclk_mux_macro].dev, false); +err: + mutex_unlock(&priv->clk_lock); return ret; } @@ -70,24 +85,31 @@ static int __bolero_reg_write(struct bolero_priv *priv, u16 macro_id, u16 reg, u8 val) { int ret = -EINVAL; + u16 current_mclk_mux_macro; - if (!priv->macro_params[macro_id].mclk_fn) { + mutex_lock(&priv->clk_lock); + current_mclk_mux_macro = + priv->current_mclk_mux_macro[macro_id]; + if (!priv->macro_params[current_mclk_mux_macro].mclk_fn) { dev_dbg_ratelimited(priv->dev, - "%s: mclk_fn not init for macro-id-%d\n", - __func__, macro_id); - return ret; + "%s: mclk_fn not init for macro-id:%d, current_mclk_mux_macro:%d\n", + __func__, macro_id, current_mclk_mux_macro); + goto err; } - ret = priv->macro_params[macro_id].mclk_fn( - priv->macro_params[macro_id].dev, true); + ret = priv->macro_params[current_mclk_mux_macro].mclk_fn( + priv->macro_params[current_mclk_mux_macro].dev, true); if (ret) { dev_dbg_ratelimited(priv->dev, - "%s: clock enable failed\n", __func__); - return ret; + "%s: clock enable failed for macro-id:%d, current_mclk_mux_macro:%d\n", + __func__, macro_id, current_mclk_mux_macro); + goto err; } bolero_ahb_write_device( priv->macro_params[macro_id].io_base, reg, val); - priv->macro_params[macro_id].mclk_fn( - priv->macro_params[macro_id].dev, false); + priv->macro_params[current_mclk_mux_macro].mclk_fn( + priv->macro_params[current_mclk_mux_macro].dev, false); +err: + mutex_unlock(&priv->clk_lock); return ret; } @@ -204,6 +226,8 @@ int bolero_register_macro(struct device *dev, u16 macro_id, priv->macro_params[macro_id].dai_ptr = ops->dai_ptr; priv->macro_params[macro_id].mclk_fn = ops->mclk_fn; priv->macro_params[macro_id].dev = dev; + priv->current_mclk_mux_macro[macro_id] = + bolero_mclk_mux_tbl[macro_id][MCLK_MUX0]; priv->num_dais += ops->num_dais; priv->num_macros_registered++; priv->macros_supported[macro_id] = true; @@ -214,6 +238,12 @@ int bolero_register_macro(struct device *dev, u16 macro_id, dev_err(dev, "%s: copy_dais failed\n", __func__); return ret; } + if (priv->macros_supported[TX_MACRO] == false) { + bolero_mclk_mux_tbl[WSA_MACRO][MCLK_MUX0] = WSA_MACRO; + priv->current_mclk_mux_macro[WSA_MACRO] = WSA_MACRO; + bolero_mclk_mux_tbl[VA_MACRO][MCLK_MUX0] = VA_MACRO; + priv->current_mclk_mux_macro[VA_MACRO] = VA_MACRO; + } ret = snd_soc_register_codec(dev->parent, &bolero, priv->bolero_dais, priv->num_dais); if (ret < 0) { @@ -265,6 +295,100 @@ void bolero_unregister_macro(struct device *dev, u16 macro_id) } EXPORT_SYMBOL(bolero_unregister_macro); +/** + * bolero_request_clock - request for clock enable/disable + * + * @dev: macro device ptr. + * @macro_id: ID of macro calling this API. + * @mclk_mux_id: MCLK_MUX ID. + * @enable: enable or disable clock flag + * + * Returns 0 on success or -EINVAL on error. + */ +int bolero_request_clock(struct device *dev, u16 macro_id, + enum mclk_mux mclk_mux_id, + bool enable) +{ + struct bolero_priv *priv; + u16 mclk_mux0_macro, mclk_mux1_macro; + int ret = 0; + + if (!dev) { + pr_err("%s: dev is null\n", __func__); + return -EINVAL; + } + if (!bolero_is_valid_macro_dev(dev)) { + dev_err(dev, "%s: macro:%d not in valid registered macro-list\n", + __func__, macro_id); + return -EINVAL; + } + priv = dev_get_drvdata(dev->parent); + if (!priv || (macro_id >= MAX_MACRO)) { + dev_err(dev, "%s: priv is null or invalid macro\n", __func__); + return -EINVAL; + } + mclk_mux0_macro = bolero_mclk_mux_tbl[macro_id][MCLK_MUX0]; + mutex_lock(&priv->clk_lock); + switch (mclk_mux_id) { + case MCLK_MUX0: + ret = priv->macro_params[mclk_mux0_macro].mclk_fn( + priv->macro_params[mclk_mux0_macro].dev, enable); + if (ret < 0) { + dev_err(dev, + "%s: MCLK_MUX0 %s failed for macro:%d, mclk_mux0_macro:%d\n", + __func__, + enable ? "enable" : "disable", + macro_id, mclk_mux0_macro); + goto err; + } + break; + case MCLK_MUX1: + mclk_mux1_macro = bolero_mclk_mux_tbl[macro_id][MCLK_MUX1]; + ret = priv->macro_params[mclk_mux0_macro].mclk_fn( + priv->macro_params[mclk_mux0_macro].dev, + true); + if (ret < 0) { + dev_err(dev, + "%s: MCLK_MUX0 en failed for macro:%d mclk_mux0_macro:%d\n", + __func__, macro_id, mclk_mux0_macro); + goto err; + } + ret = priv->macro_params[mclk_mux1_macro].mclk_fn( + priv->macro_params[mclk_mux1_macro].dev, enable); + if (ret < 0) { + dev_err(dev, + "%s: MCLK_MUX1 %s failed for macro:%d, mclk_mux1_macro:%d\n", + __func__, + enable ? "enable" : "disable", + macro_id, mclk_mux1_macro); + priv->macro_params[mclk_mux0_macro].mclk_fn( + priv->macro_params[mclk_mux0_macro].dev, + false); + goto err; + } + priv->macro_params[mclk_mux0_macro].mclk_fn( + priv->macro_params[mclk_mux0_macro].dev, + false); + break; + case MCLK_MUX_MAX: + default: + dev_err(dev, "%s: invalid mclk_mux_id: %d\n", + __func__, mclk_mux_id); + ret = -EINVAL; + goto err; + } + if (enable) + priv->current_mclk_mux_macro[macro_id] = + bolero_mclk_mux_tbl[macro_id][mclk_mux_id]; + else + priv->current_mclk_mux_macro[macro_id] = + bolero_mclk_mux_tbl[macro_id][MCLK_MUX0]; +err: + mutex_unlock(&priv->clk_lock); + return ret; +} +EXPORT_SYMBOL(bolero_request_clock); + static int bolero_soc_codec_probe(struct snd_soc_codec *codec) { struct bolero_priv *priv = dev_get_drvdata(codec->dev); @@ -359,8 +483,6 @@ static void bolero_add_child_devices(struct work_struct *work) fail_pdev_add: for (i = cnt; i > 0; i--) platform_device_put(priv->pdev_child_devices[i - 1]); -err: - return; } static int bolero_probe(struct platform_device *pdev) @@ -405,6 +527,7 @@ static int bolero_probe(struct platform_device *pdev) dev_set_drvdata(&pdev->dev, priv); mutex_init(&priv->io_lock); + mutex_init(&priv->clk_lock); INIT_WORK(&priv->bolero_add_child_devices_work, bolero_add_child_devices); schedule_work(&priv->bolero_add_child_devices_work); @@ -420,6 +543,7 @@ static int bolero_remove(struct platform_device *pdev) for (i = priv->child_num; i > 0; i--) platform_device_unregister(priv->pdev_child_devices[i - 1]); mutex_destroy(&priv->io_lock); + mutex_destroy(&priv->clk_lock); return 0; } diff --git a/asoc/codecs/bolero/bolero_cdc.h b/asoc/codecs/bolero/bolero_cdc.h index 7b3aad2a52e4..e8b8bb46a061 100644 --- a/asoc/codecs/bolero/bolero_cdc.h +++ b/asoc/codecs/bolero/bolero_cdc.h @@ -25,6 +25,12 @@ enum { MAX_MACRO }; +enum mclk_mux { + MCLK_MUX0, + MCLK_MUX1, + MCLK_MUX_MAX +}; + struct macro_ops { int (*init)(struct snd_soc_codec *codec); int (*exit)(struct snd_soc_codec *codec); @@ -40,6 +46,9 @@ int bolero_register_macro(struct device *dev, u16 macro_id, struct macro_ops *ops); void bolero_unregister_macro(struct device *dev, u16 macro_id); struct device *bolero_get_device_ptr(struct device *dev, u16 macro_id); +int bolero_request_clock(struct device *dev, u16 macro_id, + enum mclk_mux mclk_mux_id, + bool enable); #else static inline int bolero_register_macro(struct device *dev, u16 macro_id, @@ -53,9 +62,15 @@ static inline void bolero_unregister_macro(struct device *dev, u16 macro_id) } static inline struct device *bolero_get_device_ptr(struct device *dev, - u16 macro_id) + u16 macro_id) { return NULL; } +static inline int bolero_request_clock(struct device *dev, u16 macro_id, + enum mclk_mux mclk_mux_id, + bool enable) +{ + return 0; +} #endif /* CONFIG_SND_SOC_BOLERO */ #endif /* BOLERO_CDC_H */ diff --git a/asoc/codecs/bolero/internal.h b/asoc/codecs/bolero/internal.h index 63266a84c7b4..0fca99439652 100644 --- a/asoc/codecs/bolero/internal.h +++ b/asoc/codecs/bolero/internal.h @@ -27,6 +27,7 @@ struct bolero_priv { struct snd_soc_codec *codec; struct regmap *regmap; struct mutex io_lock; + struct mutex clk_lock; bool va_without_decimation; bool macros_supported[MAX_MACRO]; struct macro_ops macro_params[MAX_MACRO]; @@ -34,6 +35,7 @@ struct bolero_priv { u16 num_dais; u16 num_macros_registered; u16 child_num; + u16 current_mclk_mux_macro[MAX_MACRO]; struct platform_device *pdev_child_devices[MAX_MACRO]; struct work_struct bolero_add_child_devices_work;