static int cpwd_probe()

in cpwd.c [513:615]


static int cpwd_probe(struct platform_device *op)
{
	struct device_node *options;
	const char *str_prop;
	const void *prop_val;
	int i, err = -EINVAL;
	struct cpwd *p;

	if (cpwd_device)
		return -EINVAL;

	p = devm_kzalloc(&op->dev, sizeof(*p), GFP_KERNEL);
	if (!p)
		return -ENOMEM;

	p->irq = op->archdata.irqs[0];

	spin_lock_init(&p->lock);

	p->regs = of_ioremap(&op->resource[0], 0,
			     4 * WD_TIMER_REGSZ, DRIVER_NAME);
	if (!p->regs) {
		pr_err("Unable to map registers\n");
		return -ENOMEM;
	}

	options = of_find_node_by_path("/options");
	if (!options) {
		err = -ENODEV;
		pr_err("Unable to find /options node\n");
		goto out_iounmap;
	}

	prop_val = of_get_property(options, "watchdog-enable?", NULL);
	p->enabled = (prop_val ? true : false);

	prop_val = of_get_property(options, "watchdog-reboot?", NULL);
	p->reboot = (prop_val ? true : false);

	str_prop = of_get_property(options, "watchdog-timeout", NULL);
	if (str_prop)
		p->timeout = simple_strtoul(str_prop, NULL, 10);

	of_node_put(options);

	/* CP1400s seem to have broken PLD implementations-- the
	 * interrupt_mask register cannot be written, so no timer
	 * interrupts can be masked within the PLD.
	 */
	str_prop = of_get_property(op->dev.of_node, "model", NULL);
	p->broken = (str_prop && !strcmp(str_prop, WD_BADMODEL));

	if (!p->enabled)
		cpwd_toggleintr(p, -1, WD_INTR_OFF);

	for (i = 0; i < WD_NUMDEVS; i++) {
		static const char *cpwd_names[] = { "RIC", "XIR", "POR" };
		static int *parms[] = { &wd0_timeout,
					&wd1_timeout,
					&wd2_timeout };
		struct miscdevice *mp = &p->devs[i].misc;

		mp->minor = WD0_MINOR + i;
		mp->name = cpwd_names[i];
		mp->fops = &cpwd_fops;

		p->devs[i].regs = p->regs + (i * WD_TIMER_REGSZ);
		p->devs[i].intr_mask = (WD0_INTR_MASK << i);
		p->devs[i].runstatus &= ~WD_STAT_BSTOP;
		p->devs[i].runstatus |= WD_STAT_INIT;
		p->devs[i].timeout = p->timeout;
		if (*parms[i])
			p->devs[i].timeout = *parms[i];

		err = misc_register(&p->devs[i].misc);
		if (err) {
			pr_err("Could not register misc device for dev %d\n",
			       i);
			goto out_unregister;
		}
	}

	if (p->broken) {
		timer_setup(&cpwd_timer, cpwd_brokentimer, 0);
		cpwd_timer.expires	= WD_BTIMEOUT;

		pr_info("PLD defect workaround enabled for model %s\n",
			WD_BADMODEL);
	}

	platform_set_drvdata(op, p);
	cpwd_device = p;
	return 0;

out_unregister:
	for (i--; i >= 0; i--)
		misc_deregister(&p->devs[i].misc);

out_iounmap:
	of_iounmap(&op->resource[0], p->regs, 4 * WD_TIMER_REGSZ);

	return err;
}