[alsa-devel] [PATCH 4/6] ASoC: Intel: Skylake: Register clock device and ops
Subhransu S. Prusty
subhransu.s.prusty at intel.com
Fri Sep 8 05:31:36 CEST 2017
On Thu, Sep 07, 2017 at 08:48:38PM -0500, Pierre-Louis Bossart wrote:
>
>
> On 09/07/2017 09:29 AM, Subhransu S. Prusty wrote:
> >From: Jaikrishna Nemallapudi <jaikrishnax.nemallapudi at intel.com>
> >
> >Create a platform device and register the clock ops. Clock
> >prepare/unprepare are used to enable/disable the clock as the IPC will be
> >sent in non-atomic context. The clk set_dma_control IPC structures are
> >populated during the set_rate callback and IPC is sent to enable the clock
> >during prepare callback.
> >
> [snip]
> >+
> >+static int skl_clk_prepare(void *pvt_data, u32 id, unsigned long rate)
> >+{
> >+ struct skl *skl = pvt_data;
> >+ struct skl_clk_rate_cfg_table *rcfg;
> >+ int vbus_id, clk_type, ret;
> >+
> >+ clk_type = skl_get_clk_type(id);
> >+ if (clk_type < 0)
> >+ return -EINVAL;
> >+
> >+ ret = skl_get_vbus_id(id, clk_type);
> >+ if (ret < 0)
> >+ return ret;
> >+
> >+ vbus_id = ret;
> >+
> >+ rcfg = skl_get_rate_cfg(skl_ssp_clks[id].rate_cfg, rate);
> >+ if (!rcfg)
> >+ return -EINVAL;
> >+
> >+ ret = skl_send_clk_dma_control(skl, rcfg, vbus_id, clk_type, true);
> >+
> >+ return ret;
> >+}
> In this patchset, the clocks are configured from the machine driver,
> and the enable/disable conveniently placed in
> platform_clock_control() or hw_params(), where the DSP is most
> likely active.
> If you expose a clock, codec driver implementers may want to use
> them directly instead of relying on a machine driver. A number of
> existing codecs do use the clk API, so there could be a case where a
> codec driver calls devm_clk_get and clk_prepare_enable(), without
> any ability to know what state the DSP is in.
> What happens then if the DSP is in suspend? Does this force it back
> to D0? Does the virtual clock driver return an error? Or are you
> using the clk API with some restrictions on when the clock can be
> configured?
No, clk enable will not force the DSP to D0. So if the DSP is not active,
the IPC will timeout and error will be propagated to the caller.
>
> Note that I am not against this idea, it's fine, but I'd like more
> clarity on the assumptions. Thanks!
I agree. I will add some comments explaining the expectation.
Thanks
Subhransu
>
> >+
> >+static int skl_clk_unprepare(void *pvt_data, u32 id, unsigned long rate)
> >+{
> >+ struct skl *skl = pvt_data;
> >+ struct skl_clk_rate_cfg_table *rcfg;
> >+ int vbus_id, ret;
> >+ u8 clk_type;
> >+
> >+ clk_type = skl_get_clk_type(id);
> >+ ret = skl_get_vbus_id(id, clk_type);
> >+ if (ret < 0)
> >+ return ret;
> >+
> >+ vbus_id = ret;
> >+
> >+ rcfg = skl_get_rate_cfg(skl_ssp_clks[id].rate_cfg, rate);
> >+ if (!rcfg)
> >+ return -EINVAL;
> >+
> >+ return skl_send_clk_dma_control(skl, rcfg, vbus_id, clk_type, false);
> >+}
> >+
> >+static int skl_clk_set_rate(u32 id, unsigned long rate)
> >+{
> >+ struct skl_clk_rate_cfg_table *rcfg;
> >+ u8 clk_type;
> >+
> >+ if (!rate)
> >+ return -EINVAL;
> >+
> >+ clk_type = skl_get_clk_type(id);
> >+ rcfg = skl_get_rate_cfg(skl_ssp_clks[id].rate_cfg, rate);
> >+ if (!rcfg)
> >+ return -EINVAL;
> >+
> >+ skl_fill_clk_ipc(rcfg, clk_type);
> >+
> >+ return 0;
> >+}
> >+
> >+unsigned long skl_clk_recalc_rate(u32 id, unsigned long parent_rate)
> >+{
> >+ struct skl_clk_rate_cfg_table *rcfg;
> >+ u8 clk_type;
> >+
> >+ clk_type = skl_get_clk_type(id);
> >+ rcfg = skl_get_rate_cfg(skl_ssp_clks[id].rate_cfg, parent_rate);
> >+ if (!rcfg)
> >+ return 0;
> >+
> >+ skl_fill_clk_ipc(rcfg, clk_type);
> >+
> >+ return rcfg->rate;
> >+}
> >+
> > static int skl_machine_device_register(struct skl *skl, void *driver_data)
> > {
> > struct hdac_bus *bus = ebus_to_hbus(&skl->ebus);
> >@@ -555,10 +682,21 @@ void init_skl_xtal_rate(int pci_id)
> > }
> > }
> >+/*
> >+ * prepare/unprepare are used instead of enable/disable as IPC will be sent
> >+ * in non-atomic context.
> >+ */
> >+static struct skl_clk_ops clk_ops = {
> >+ .prepare = skl_clk_prepare,
> >+ .unprepare = skl_clk_unprepare,
> >+ .set_rate = skl_clk_set_rate,
> >+ .recalc_rate = skl_clk_recalc_rate,
> >+};
> >+
> > static int skl_clock_device_register(struct skl *skl)
> > {
> > struct skl_clk_pdata *clk_pdata;
> >-
> >+ struct platform_device_info pdevinfo = {NULL};
> > clk_pdata = devm_kzalloc(&skl->pci->dev, sizeof(*clk_pdata),
> > GFP_KERNEL);
> >@@ -573,10 +711,28 @@ static int skl_clock_device_register(struct skl *skl)
> > /* Query NHLT to fill the rates and parent */
> > skl_get_clks(skl, clk_pdata->ssp_clks);
> >+ clk_pdata->ops = &clk_ops;
> >+ clk_pdata->pvt_data = skl;
> >+
> >+ /* Register Platform device */
> >+ pdevinfo.parent = &skl->pci->dev;
> >+ pdevinfo.id = -1;
> >+ pdevinfo.name = "skl-ssp-clk";
> >+ pdevinfo.data = clk_pdata;
> >+ pdevinfo.size_data = sizeof(*clk_pdata);
> >+ skl->clk_dev = platform_device_register_full(&pdevinfo);
> >+ if (IS_ERR(skl->clk_dev))
> >+ return PTR_ERR(skl->clk_dev);
> > return 0;
> > }
> >+static void skl_clock_device_unregister(struct skl *skl)
> >+{
> >+ if (skl->clk_dev)
> >+ platform_device_unregister(skl->clk_dev);
> >+}
> >+
> > /*
> > * Probe the given codec address
> > */
> >@@ -859,6 +1015,11 @@ static int skl_probe(struct pci_dev *pci,
> > /* check if dsp is there */
> > if (bus->ppcap) {
> >+ /* create device for dsp clk */
> >+ err = skl_clock_device_register(skl);
> >+ if (err < 0)
> >+ goto out_clk_free;
> >+
> > err = skl_machine_device_register(skl,
> > (void *)pci_id->driver_data);
> > if (err < 0)
> >@@ -890,6 +1051,8 @@ static int skl_probe(struct pci_dev *pci,
> > skl_free_dsp(skl);
> > out_mach_free:
> > skl_machine_device_unregister(skl);
> >+out_clk_free:
> >+ skl_clock_device_unregister(skl);
> > out_nhlt_free:
> > skl_nhlt_free(skl->nhlt);
> > out_free:
> >@@ -940,6 +1103,7 @@ static void skl_remove(struct pci_dev *pci)
> > skl_free_dsp(skl);
> > skl_machine_device_unregister(skl);
> > skl_dmic_device_unregister(skl);
> >+ skl_clock_device_unregister(skl);
> > skl_nhlt_remove_sysfs(skl);
> > skl_nhlt_free(skl->nhlt);
> > skl_free(ebus);
> >diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h
> >index f06e98962a0b..df0fcf1bfe40 100644
> >--- a/sound/soc/intel/skylake/skl.h
> >+++ b/sound/soc/intel/skylake/skl.h
> >@@ -57,6 +57,7 @@ struct skl {
> > unsigned int init_done:1; /* delayed init status */
> > struct platform_device *dmic_dev;
> > struct platform_device *i2s_dev;
> >+ struct platform_device *clk_dev;
> > struct snd_soc_platform *platform;
> > struct nhlt_acpi_table *nhlt; /* nhlt ptr */
>
--
More information about the Alsa-devel
mailing list