static int omap_hwspinlock_probe()

in omap_hwspinlock.c [75:148]


static int omap_hwspinlock_probe(struct platform_device *pdev)
{
	struct device_node *node = pdev->dev.of_node;
	struct hwspinlock_device *bank;
	struct hwspinlock *hwlock;
	void __iomem *io_base;
	int num_locks, i, ret;
	/* Only a single hwspinlock block device is supported */
	int base_id = 0;

	if (!node)
		return -ENODEV;

	io_base = devm_platform_ioremap_resource(pdev, 0);
	if (IS_ERR(io_base))
		return PTR_ERR(io_base);

	/*
	 * make sure the module is enabled and clocked before reading
	 * the module SYSSTATUS register
	 */
	pm_runtime_enable(&pdev->dev);
	ret = pm_runtime_get_sync(&pdev->dev);
	if (ret < 0) {
		pm_runtime_put_noidle(&pdev->dev);
		goto runtime_err;
	}

	/* Determine number of locks */
	i = readl(io_base + SYSSTATUS_OFFSET);
	i >>= SPINLOCK_NUMLOCKS_BIT_OFFSET;

	/*
	 * runtime PM will make sure the clock of this module is
	 * enabled again iff at least one lock is requested
	 */
	ret = pm_runtime_put(&pdev->dev);
	if (ret < 0)
		goto runtime_err;

	/* one of the four lsb's must be set, and nothing else */
	if (hweight_long(i & 0xf) != 1 || i > 8) {
		ret = -EINVAL;
		goto runtime_err;
	}

	num_locks = i * 32; /* actual number of locks in this device */

	bank = devm_kzalloc(&pdev->dev, struct_size(bank, lock, num_locks),
			    GFP_KERNEL);
	if (!bank) {
		ret = -ENOMEM;
		goto runtime_err;
	}

	platform_set_drvdata(pdev, bank);

	for (i = 0, hwlock = &bank->lock[0]; i < num_locks; i++, hwlock++)
		hwlock->priv = io_base + LOCK_BASE_OFFSET + sizeof(u32) * i;

	ret = hwspin_lock_register(bank, &pdev->dev, &omap_hwspinlock_ops,
						base_id, num_locks);
	if (ret)
		goto runtime_err;

	dev_dbg(&pdev->dev, "Registered %d locks with HwSpinlock core\n",
		num_locks);

	return 0;

runtime_err:
	pm_runtime_disable(&pdev->dev);
	return ret;
}