drivers/watchdog/cpwd.c

Source file repositories/reference/linux-study-clean/drivers/watchdog/cpwd.c

File Facts

System
Linux kernel
Corpus path
drivers/watchdog/cpwd.c
Extension
.c
Size
15878 bytes
Lines
660
Domain
Driver Families
Bucket
drivers/watchdog
Inferred role
Driver Families: operation-table or driver-model contract
Status
pattern implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

static const struct file_operations cpwd_fops = {
	.owner =		THIS_MODULE,
	.unlocked_ioctl =	cpwd_ioctl,
	.compat_ioctl =		cpwd_compat_ioctl,
	.open =			cpwd_open,
	.write =		cpwd_write,
	.read =			cpwd_read,
	.release =		cpwd_release,
};

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;
		}

Annotation

Implementation Notes