static int mvebu_pwm_probe()

in gpio-mvebu.c [783:885]


static int mvebu_pwm_probe(struct platform_device *pdev,
			   struct mvebu_gpio_chip *mvchip,
			   int id)
{
	struct device *dev = &pdev->dev;
	struct mvebu_pwm *mvpwm;
	void __iomem *base;
	u32 offset;
	u32 set;

	if (of_device_is_compatible(mvchip->chip.of_node,
				    "marvell,armada-370-gpio")) {
		/*
		 * There are only two sets of PWM configuration registers for
		 * all the GPIO lines on those SoCs which this driver reserves
		 * for the first two GPIO chips. So if the resource is missing
		 * we can't treat it as an error.
		 */
		if (!platform_get_resource_byname(pdev, IORESOURCE_MEM, "pwm"))
			return 0;
		offset = 0;
	} else if (mvchip->soc_variant == MVEBU_GPIO_SOC_VARIANT_A8K) {
		int ret = of_property_read_u32(dev->of_node,
					       "marvell,pwm-offset", &offset);
		if (ret < 0)
			return 0;
	} else {
		return 0;
	}

	if (IS_ERR(mvchip->clk))
		return PTR_ERR(mvchip->clk);

	mvpwm = devm_kzalloc(dev, sizeof(struct mvebu_pwm), GFP_KERNEL);
	if (!mvpwm)
		return -ENOMEM;
	mvchip->mvpwm = mvpwm;
	mvpwm->mvchip = mvchip;
	mvpwm->offset = offset;

	if (mvchip->soc_variant == MVEBU_GPIO_SOC_VARIANT_A8K) {
		mvpwm->regs = mvchip->regs;

		switch (mvchip->offset) {
		case AP80X_GPIO0_OFF_A8K:
		case CP11X_GPIO0_OFF_A8K:
			/* Blink counter A */
			set = 0;
			break;
		case CP11X_GPIO1_OFF_A8K:
			/* Blink counter B */
			set = U32_MAX;
			mvpwm->offset += PWM_BLINK_COUNTER_B_OFF;
			break;
		default:
			return -EINVAL;
		}
	} else {
		base = devm_platform_ioremap_resource_byname(pdev, "pwm");
		if (IS_ERR(base))
			return PTR_ERR(base);

		mvpwm->regs = devm_regmap_init_mmio(&pdev->dev, base,
						    &mvebu_gpio_regmap_config);
		if (IS_ERR(mvpwm->regs))
			return PTR_ERR(mvpwm->regs);

		/*
		 * Use set A for lines of GPIO chip with id 0, B for GPIO chip
		 * with id 1. Don't allow further GPIO chips to be used for PWM.
		 */
		if (id == 0)
			set = 0;
		else if (id == 1)
			set = U32_MAX;
		else
			return -EINVAL;
	}

	regmap_write(mvchip->regs,
		     GPIO_BLINK_CNT_SELECT_OFF + mvchip->offset, set);

	mvpwm->clk_rate = clk_get_rate(mvchip->clk);
	if (!mvpwm->clk_rate) {
		dev_err(dev, "failed to get clock rate\n");
		return -EINVAL;
	}

	mvpwm->chip.dev = dev;
	mvpwm->chip.ops = &mvebu_pwm_ops;
	mvpwm->chip.npwm = mvchip->chip.ngpio;
	/*
	 * There may already be some PWM allocated, so we can't force
	 * mvpwm->chip.base to a fixed point like mvchip->chip.base.
	 * So, we let pwmchip_add() do the numbering and take the next free
	 * region.
	 */
	mvpwm->chip.base = -1;

	spin_lock_init(&mvpwm->lock);

	return pwmchip_add(&mvpwm->chip);
}