[RFC PATCH v2 2/2] drivers: mfd: vexpress: add Serial Power Controller (SPC) support
Jon Medhurst (Tixy)
tixy at linaro.org
Wed Jun 5 14:08:33 EDT 2013
On Wed, 2013-06-05 at 12:46 +0100, Lorenzo Pieralisi wrote:
[...]
> +static const struct of_device_id vexpress_spc_ids[] __initconst = {
> + { .compatible = "arm,vexpress-spc,v2p-ca15_a7" },
> + { .compatible = "arm,vexpress-spc" },
> + {},
> +};
> +
> +static int __init vexpress_spc_init(void)
> +{
> + int ret;
> + struct device_node *node = of_find_matching_node(NULL,
> + vexpress_spc_ids);
To allow for devices without an SPC we should check for !node here and
bail out, otherwise we get an ugly message from the WARN_ON further
down. I see this on RTSM, and multiplatform kernels would suffer this as
well.
Even if the ugly warning wasn't there, it still seems cleaner to me to
have a proper check for an absent spc node.
> + info = kzalloc(sizeof(*info), GFP_KERNEL);
> + if (!info) {
> + pr_err("%s: unable to allocate mem\n", __func__);
> + return -ENOMEM;
> + }
> + info->cur_req_type = INVALID_TYPE;
> +
> + info->baseaddr = of_iomap(node, 0);
> + if (WARN_ON(!info->baseaddr)) {
> + ret = -ENXIO;
> + goto mem_free;
> + }
> +
> + info->irq = irq_of_parse_and_map(node, 0);
> +
> + if (WARN_ON(!info->irq)) {
> + ret = -ENXIO;
> + goto unmap;
> + }
> +
> + readl_relaxed(info->baseaddr + PWC_STATUS);
> +
> + ret = request_irq(info->irq, vexpress_spc_irq_handler,
> + IRQF_DISABLED | IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
> + "arm-spc", info);
> +
> + if (ret) {
> + pr_err("IRQ %d request failed\n", info->irq);
> + ret = -ENODEV;
> + goto unmap;
> + }
> +
> + info->a15_clusid = readl_relaxed(info->baseaddr + A15_CONF) & 0xf;
> +
> + vexpress_spc_config_bridge = vexpress_config_bridge_register(
> + node, &vexpress_spc_config_bridge_info);
> +
> + if (WARN_ON(!vexpress_spc_config_bridge)) {
> + ret = -ENODEV;
> + goto unmap;
> + }
> +
> + opp_func = vexpress_config_func_get(vexpress_spc_config_bridge, "opp");
> + perf_func =
> + vexpress_config_func_get(vexpress_spc_config_bridge, "perf");
> +
> + if (!opp_func || !perf_func) {
> + ret = -ENODEV;
> + goto unmap;
> + }
> +
> + if (vexpress_spc_populate_opps(0) || vexpress_spc_populate_opps(1)) {
> + if (info->irq)
> + free_irq(info->irq, info);
> + pr_err("failed to build OPP table\n");
> + ret = -ENODEV;
> + goto unmap;
> + }
> + /*
> + * Multi-cluster systems may need this data when non-coherent, during
> + * cluster power-up/power-down. Make sure it reaches main memory:
> + */
> + sync_cache_w(info);
> + sync_cache_w(&info);
> + pr_info("vexpress-spc loaded at %p\n", info->baseaddr);
> + return 0;
> +
> +unmap:
> + iounmap(info->baseaddr);
> +
> +mem_free:
> + kfree(info);
> + return ret;
> +}
> +
> +static bool __init __vexpress_spc_check_loaded(void);
> +static bool (*spc_check_loaded)(void) = &__vexpress_spc_check_loaded;
> +
> +static bool __init __vexpress_spc_check_loaded(void)
> +{
> + if (vexpress_spc_load_result == -EAGAIN)
> + vexpress_spc_load_result = vexpress_spc_init();
> + spc_check_loaded = &vexpress_spc_initialized;
> + return vexpress_spc_initialized();
> +}
> +
> +/*
> + * Function exported to manage early_initcall ordering.
> + * SPC code is needed very early in the boot process
> + * to bring CPUs out of reset and initialize power
> + * management back-end. After boot swap pointers to
> + * make the functionality check available to loadable
> + * modules, when early boot init functions have been
> + * already freed from kernel address space.
> + */
> +bool vexpress_spc_check_loaded(void)
> +{
> + return spc_check_loaded();
> +}
> +EXPORT_SYMBOL_GPL(vexpress_spc_check_loaded);
> +
> +static int __init vexpress_spc_early_init(void)
> +{
> + __vexpress_spc_check_loaded();
> + return vexpress_spc_load_result;
> +}
> +early_initcall(vexpress_spc_early_init);
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("Serial Power Controller (SPC) support");
[...]
--
Tixy
More information about the linux-arm-kernel
mailing list