int __init init_common()

in qcom/tsens.c [741:925]


int __init init_common(struct tsens_priv *priv)
{
	void __iomem *tm_base, *srot_base;
	struct device *dev = priv->dev;
	u32 ver_minor;
	struct resource *res;
	u32 enabled;
	int ret, i, j;
	struct platform_device *op = of_find_device_by_node(priv->dev->of_node);

	if (!op)
		return -EINVAL;

	if (op->num_resources > 1) {
		/* DT with separate SROT and TM address space */
		priv->tm_offset = 0;
		res = platform_get_resource(op, IORESOURCE_MEM, 1);
		srot_base = devm_ioremap_resource(dev, res);
		if (IS_ERR(srot_base)) {
			ret = PTR_ERR(srot_base);
			goto err_put_device;
		}

		priv->srot_map = devm_regmap_init_mmio(dev, srot_base,
						       &tsens_srot_config);
		if (IS_ERR(priv->srot_map)) {
			ret = PTR_ERR(priv->srot_map);
			goto err_put_device;
		}
	} else {
		/* old DTs where SROT and TM were in a contiguous 2K block */
		priv->tm_offset = 0x1000;
	}

	if (tsens_version(priv) >= VER_0_1) {
		res = platform_get_resource(op, IORESOURCE_MEM, 0);
		tm_base = devm_ioremap_resource(dev, res);
		if (IS_ERR(tm_base)) {
			ret = PTR_ERR(tm_base);
			goto err_put_device;
		}

		priv->tm_map = devm_regmap_init_mmio(dev, tm_base, &tsens_config);
	} else { /* VER_0 share the same gcc regs using a syscon */
		struct device *parent = priv->dev->parent;

		if (parent)
			priv->tm_map = syscon_node_to_regmap(parent->of_node);
	}

	if (IS_ERR_OR_NULL(priv->tm_map)) {
		if (!priv->tm_map)
			ret = -ENODEV;
		else
			ret = PTR_ERR(priv->tm_map);
		goto err_put_device;
	}

	/* VER_0 have only tm_map */
	if (!priv->srot_map)
		priv->srot_map = priv->tm_map;

	if (tsens_version(priv) > VER_0_1) {
		for (i = VER_MAJOR; i <= VER_STEP; i++) {
			priv->rf[i] = devm_regmap_field_alloc(dev, priv->srot_map,
							      priv->fields[i]);
			if (IS_ERR(priv->rf[i])) {
				ret = PTR_ERR(priv->rf[i]);
				goto err_put_device;
			}
		}
		ret = regmap_field_read(priv->rf[VER_MINOR], &ver_minor);
		if (ret)
			goto err_put_device;
	}

	priv->rf[TSENS_EN] = devm_regmap_field_alloc(dev, priv->srot_map,
						     priv->fields[TSENS_EN]);
	if (IS_ERR(priv->rf[TSENS_EN])) {
		ret = PTR_ERR(priv->rf[TSENS_EN]);
		goto err_put_device;
	}
	/* in VER_0 TSENS need to be explicitly enabled */
	if (tsens_version(priv) == VER_0)
		regmap_field_write(priv->rf[TSENS_EN], 1);

	ret = regmap_field_read(priv->rf[TSENS_EN], &enabled);
	if (ret)
		goto err_put_device;
	if (!enabled) {
		dev_err(dev, "%s: device not enabled\n", __func__);
		ret = -ENODEV;
		goto err_put_device;
	}

	priv->rf[SENSOR_EN] = devm_regmap_field_alloc(dev, priv->srot_map,
						      priv->fields[SENSOR_EN]);
	if (IS_ERR(priv->rf[SENSOR_EN])) {
		ret = PTR_ERR(priv->rf[SENSOR_EN]);
		goto err_put_device;
	}
	priv->rf[INT_EN] = devm_regmap_field_alloc(dev, priv->tm_map,
						   priv->fields[INT_EN]);
	if (IS_ERR(priv->rf[INT_EN])) {
		ret = PTR_ERR(priv->rf[INT_EN]);
		goto err_put_device;
	}

	priv->rf[TSENS_SW_RST] =
		devm_regmap_field_alloc(dev, priv->srot_map, priv->fields[TSENS_SW_RST]);
	if (IS_ERR(priv->rf[TSENS_SW_RST])) {
		ret = PTR_ERR(priv->rf[TSENS_SW_RST]);
		goto err_put_device;
	}

	priv->rf[TRDY] = devm_regmap_field_alloc(dev, priv->tm_map, priv->fields[TRDY]);
	if (IS_ERR(priv->rf[TRDY])) {
		ret = PTR_ERR(priv->rf[TRDY]);
		goto err_put_device;
	}

	/* This loop might need changes if enum regfield_ids is reordered */
	for (j = LAST_TEMP_0; j <= UP_THRESH_15; j += 16) {
		for (i = 0; i < priv->feat->max_sensors; i++) {
			int idx = j + i;

			priv->rf[idx] = devm_regmap_field_alloc(dev,
								priv->tm_map,
								priv->fields[idx]);
			if (IS_ERR(priv->rf[idx])) {
				ret = PTR_ERR(priv->rf[idx]);
				goto err_put_device;
			}
		}
	}

	if (priv->feat->crit_int || tsens_version(priv) < VER_0_1) {
		/* Loop might need changes if enum regfield_ids is reordered */
		for (j = CRITICAL_STATUS_0; j <= CRIT_THRESH_15; j += 16) {
			for (i = 0; i < priv->feat->max_sensors; i++) {
				int idx = j + i;

				priv->rf[idx] =
					devm_regmap_field_alloc(dev,
								priv->tm_map,
								priv->fields[idx]);
				if (IS_ERR(priv->rf[idx])) {
					ret = PTR_ERR(priv->rf[idx]);
					goto err_put_device;
				}
			}
		}
	}

	if (tsens_version(priv) > VER_1_X &&  ver_minor > 2) {
		/* Watchdog is present only on v2.3+ */
		priv->feat->has_watchdog = 1;
		for (i = WDOG_BARK_STATUS; i <= CC_MON_MASK; i++) {
			priv->rf[i] = devm_regmap_field_alloc(dev, priv->tm_map,
							      priv->fields[i]);
			if (IS_ERR(priv->rf[i])) {
				ret = PTR_ERR(priv->rf[i]);
				goto err_put_device;
			}
		}
		/*
		 * Watchdog is already enabled, unmask the bark.
		 * Disable cycle completion monitoring
		 */
		regmap_field_write(priv->rf[WDOG_BARK_MASK], 0);
		regmap_field_write(priv->rf[CC_MON_MASK], 1);
	}

	spin_lock_init(&priv->ul_lock);

	/* VER_0 interrupt doesn't need to be enabled */
	if (tsens_version(priv) >= VER_0_1)
		tsens_enable_irq(priv);

	tsens_debug_init(op);

err_put_device:
	put_device(&op->dev);
	return ret;
}