static int ziirave_wdt_probe()

in ziirave_wdt.c [596:709]


static int ziirave_wdt_probe(struct i2c_client *client,
			     const struct i2c_device_id *id)
{
	int ret;
	struct ziirave_wdt_data *w_priv;
	int val;

	if (!i2c_check_functionality(client->adapter,
				     I2C_FUNC_SMBUS_BYTE |
				     I2C_FUNC_SMBUS_BYTE_DATA |
				     I2C_FUNC_SMBUS_WRITE_BLOCK_DATA))
		return -ENODEV;

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

	mutex_init(&w_priv->sysfs_mutex);

	w_priv->wdd.info = &ziirave_wdt_info;
	w_priv->wdd.ops = &ziirave_wdt_ops;
	w_priv->wdd.min_timeout = ZIIRAVE_TIMEOUT_MIN;
	w_priv->wdd.max_timeout = ZIIRAVE_TIMEOUT_MAX;
	w_priv->wdd.parent = &client->dev;
	w_priv->wdd.groups = ziirave_wdt_groups;

	watchdog_init_timeout(&w_priv->wdd, wdt_timeout, &client->dev);

	/*
	 * The default value set in the watchdog should be perfectly valid, so
	 * pass that in if we haven't provided one via the module parameter or
	 * of property.
	 */
	if (w_priv->wdd.timeout == 0) {
		val = i2c_smbus_read_byte_data(client, ZIIRAVE_WDT_TIMEOUT);
		if (val < 0) {
			dev_err(&client->dev, "Failed to read timeout\n");
			return val;
		}

		if (val > ZIIRAVE_TIMEOUT_MAX ||
		    val < ZIIRAVE_TIMEOUT_MIN)
			val = ZIIRAVE_TIMEOUT_DEFAULT;

		w_priv->wdd.timeout = val;
	}

	ret = ziirave_wdt_set_timeout(&w_priv->wdd, w_priv->wdd.timeout);
	if (ret) {
		dev_err(&client->dev, "Failed to set timeout\n");
		return ret;
	}

	dev_info(&client->dev, "Timeout set to %ds\n", w_priv->wdd.timeout);

	watchdog_set_nowayout(&w_priv->wdd, nowayout);

	i2c_set_clientdata(client, w_priv);

	/* If in unconfigured state, set to stopped */
	val = i2c_smbus_read_byte_data(client, ZIIRAVE_WDT_STATE);
	if (val < 0) {
		dev_err(&client->dev, "Failed to read state\n");
		return val;
	}

	if (val == ZIIRAVE_STATE_INITIAL)
		ziirave_wdt_stop(&w_priv->wdd);

	ret = ziirave_wdt_init_duration(client);
	if (ret) {
		dev_err(&client->dev, "Failed to init duration\n");
		return ret;
	}

	ret = ziirave_wdt_revision(client, &w_priv->firmware_rev,
				   ZIIRAVE_WDT_FIRM_VER_MAJOR);
	if (ret) {
		dev_err(&client->dev, "Failed to read firmware version\n");
		return ret;
	}

	dev_info(&client->dev,
		 "Firmware version: 02.%02u.%02u\n",
		 w_priv->firmware_rev.major, w_priv->firmware_rev.minor);

	ret = ziirave_wdt_revision(client, &w_priv->bootloader_rev,
				   ZIIRAVE_WDT_BOOT_VER_MAJOR);
	if (ret) {
		dev_err(&client->dev, "Failed to read bootloader version\n");
		return ret;
	}

	dev_info(&client->dev,
		 "Bootloader version: 01.%02u.%02u\n",
		 w_priv->bootloader_rev.major, w_priv->bootloader_rev.minor);

	w_priv->reset_reason = i2c_smbus_read_byte_data(client,
						ZIIRAVE_WDT_RESET_REASON);
	if (w_priv->reset_reason < 0) {
		dev_err(&client->dev, "Failed to read reset reason\n");
		return w_priv->reset_reason;
	}

	if (w_priv->reset_reason >= ARRAY_SIZE(ziirave_reasons) ||
	    !ziirave_reasons[w_priv->reset_reason]) {
		dev_err(&client->dev, "Invalid reset reason\n");
		return -ENODEV;
	}

	ret = watchdog_register_device(&w_priv->wdd);

	return ret;
}