On Tue, 02 Jan 2018, Ryder Lee wrote:

> Add a common driver for the top block of the MediaTek audio subsystem.
> This is a wrapper which manages resources for audio components.
> 
> Signed-off-by: Ryder Lee <ryder....@mediatek.com>
> ---
>  drivers/mfd/Kconfig      |   9 ++++
>  drivers/mfd/Makefile     |   2 +
>  drivers/mfd/mtk-audsys.c | 138 
> +++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 149 insertions(+)
>  create mode 100644 drivers/mfd/mtk-audsys.c
> 
> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> index 1d20a80..ea50b51 100644
> --- a/drivers/mfd/Kconfig
> +++ b/drivers/mfd/Kconfig
> @@ -368,6 +368,15 @@ config MFD_MC13XXX_I2C
>       help
>         Select this if your MC13xxx is connected via an I2C bus.
>  
> +config MFD_MEDIATEK_AUDSYS
> +     tristate "MediaTek audio subsystem interface"
> +     select MDF_CORE
> +     select REGMAP_MMIO
> +     help
> +       Select this if you have a audio subsystem in MediaTek SoC.
> +       The audio subsystem has at least a clock driver part and some
> +       audio components.
> +
>  config MFD_MXS_LRADC
>       tristate "Freescale i.MX23/i.MX28 LRADC"
>       depends on ARCH_MXS || COMPILE_TEST
> diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
> index d9474ad..3e20927 100644
> --- a/drivers/mfd/Makefile
> +++ b/drivers/mfd/Makefile
> @@ -101,6 +101,8 @@ obj-$(CONFIG_MFD_MC13XXX) += mc13xxx-core.o
>  obj-$(CONFIG_MFD_MC13XXX_SPI)        += mc13xxx-spi.o
>  obj-$(CONFIG_MFD_MC13XXX_I2C)        += mc13xxx-i2c.o
>  
> +obj-$(CONFIG_MFD_MEDIATEK_AUDSYS) += mtk-audsys.o
> +
>  obj-$(CONFIG_MFD_CORE)               += mfd-core.o
>  
>  obj-$(CONFIG_EZX_PCAP)               += ezx-pcap.o
> diff --git a/drivers/mfd/mtk-audsys.c b/drivers/mfd/mtk-audsys.c
> new file mode 100644
> index 0000000..89399e1
> --- /dev/null
> +++ b/drivers/mfd/mtk-audsys.c
> @@ -0,0 +1,138 @@
> +/*
> + * Mediatek audio subsystem core driver
> + *
> + *  Copyright (c) 2017 MediaTek Inc.
> + *
> + * Author: Ryder Lee <ryder....@mediatek.com>
> + *
> + * For licencing details see kernel-base/COPYING

You can't do that.

Grep for SPDX to see what is expected.

> + *
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/module.h>
> +#include <linux/of_platform.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +
> +#define AUDSYS_MAX_CLK_NUM 3

When is this not 3?

> +struct sys_dev {
> +     struct device *dev;
> +     struct regmap *regmap;
> +     int clk_num;
> +     struct clk *clks[];
> +};
> +
> +static const struct regmap_config aud_regmap_config = {
> +     .reg_bits = 32,
> +     .reg_stride = 4,
> +     .val_bits = 32,
> +     .max_register = 0x15e0,
> +     .cache_type = REGCACHE_NONE,
> +};
> +
> +static int mtk_subsys_enable(struct sys_dev *sys)
> +{
> +     struct device *dev = sys->dev;

I would remove dev and regmap from the sys_dev struct and pass in pdev
directly into this function.  Then use platform_get_drvdata() as you
did in .remove().

> +     struct clk *clk;
> +     int i, ret;
> +
> +     for (i = 0; i < sys->clk_num; i++) {
> +             clk = of_clk_get(dev->of_node, i);
> +             if (IS_ERR(clk)) {
> +                     if (PTR_ERR(clk) == -EPROBE_DEFER)
> +                             return -EPROBE_DEFER;
> +                     break;
> +             }
> +             sys->clks[i] = clk;
> +     }
> +
> +     for (i = 0; i < sys->clk_num && sys->clks[i]; i++) {

Why do you need a separate loop for this?

Just prepare and enable valid clocks in the for() loop above.

> +             ret = clk_prepare_enable(sys->clks[i]);
> +             if (ret)
> +                     goto err_enable_clks;
> +     }
> +
> +     return 0;
> +
> +err_enable_clks:
> +     while (--i >= 0)
> +             clk_disable_unprepare(sys->clks[i]);
> +
> +     return ret;
> +}
> +
> +static int mtk_subsys_probe(struct platform_device *pdev)
> +{
> +     struct sys_dev *sys;
> +     struct resource *res;
> +     void __iomem *mmio;
> +     int num, ret;
> +
> +     num = (int)of_device_get_match_data(&pdev->dev);
> +     if (!num)
> +             return -EINVAL;

This is a very rigid method of achieving your aim.  Please find a way
to make this more dynamic.  You're probably better off counting the
elements within the property, checking to ensure there aren't more
than the maximum pre-allocated/allowed clocks, then using the number
gleaned directly from the Device Tree.

> +     sys = devm_kzalloc(&pdev->dev, sizeof(*sys) +
> +                        sizeof(struct clk *) * num, GFP_KERNEL);

You need to add bracketing here for clarity.

> +     if (!sys)
> +             return -ENOMEM;
> +
> +     sys->clk_num = num;
> +     sys->dev = &pdev->dev;

Why are you saving the device pointer?

> +     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +     mmio = devm_ioremap_resource(sys->dev, res);
> +     if (IS_ERR(mmio))
> +             return PTR_ERR(mmio);
> +
> +     sys->regmap = devm_regmap_init_mmio(sys->dev, mmio,
> +                                         &aud_regmap_config);

Why are you saving a devm'ed regmap pointer?

> +     if (IS_ERR(sys->regmap))
> +             return PTR_ERR(sys->regmap);
> +
> +     platform_set_drvdata(pdev, sys);
> +
> +     /* Enable top level clocks */
> +     ret = mtk_subsys_enable(sys);

mtk_subsys_enable_clks()

> +     if (ret)
> +             return ret;
> +
> +     return devm_of_platform_populate(sys->dev);
> +};
> +
> +static int mtk_subsys_remove(struct platform_device *pdev)
> +{
> +     struct sys_dev *sys = platform_get_drvdata(pdev);
> +     int i;
> +
> +     for (i = sys->clk_num - 1; i >= 0; i--)
> +             if (sys->clks[i])

This check is superfluous as the clk subsystem does this for you.

> +                     clk_disable_unprepare(sys->clks[i]);
> +
> +     return 0;
> +}
> +
> +static const struct of_device_id of_match_audsys[] = {
> +     {
> +       .compatible = "mediatek,mt2701-audsys-core",
> +       .data = (void *)AUDSYS_MAX_CLK_NUM,

You can remove this line.

> +     },
> +     {},
> +};
> +MODULE_DEVICE_TABLE(platform, of_match_audsys);
> +
> +static struct platform_driver audsys_drv = {
> +     .probe = mtk_subsys_probe,
> +     .remove = mtk_subsys_remove,
> +     .driver = {
> +             .name = "mediatek-audsys-core",
> +             .of_match_table = of_match_ptr(of_match_audsys),
> +     },
> +};
> +
> +builtin_platform_driver(audsys_drv);
> +
> +MODULE_DESCRIPTION("Mediatek audio subsystem core driver");

> +MODULE_LICENSE("GPL");

<just_checking>
  Are you sure this is what you want?
</just_checking>

-- 
Lee Jones
Linaro Services Technical Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

Reply via email to