static int of_get_devfreq_events()

in event/exynos-ppmu.c [503:597]


static int of_get_devfreq_events(struct device_node *np,
				 struct exynos_ppmu *info)
{
	struct devfreq_event_desc *desc;
	struct device *dev = info->dev;
	struct device_node *events_np, *node;
	int i, j, count;
	const struct of_device_id *of_id;
	int ret;

	events_np = of_get_child_by_name(np, "events");
	if (!events_np) {
		dev_err(dev,
			"failed to get child node of devfreq-event devices\n");
		return -EINVAL;
	}

	count = of_get_child_count(events_np);
	desc = devm_kcalloc(dev, count, sizeof(*desc), GFP_KERNEL);
	if (!desc)
		return -ENOMEM;
	info->num_events = count;

	of_id = of_match_device(exynos_ppmu_id_match, dev);
	if (of_id)
		info->ppmu_type = (enum exynos_ppmu_type)of_id->data;
	else
		return -EINVAL;

	j = 0;
	for_each_child_of_node(events_np, node) {
		for (i = 0; i < ARRAY_SIZE(ppmu_events); i++) {
			if (!ppmu_events[i].name)
				continue;

			if (of_node_name_eq(node, ppmu_events[i].name))
				break;
		}

		if (i == ARRAY_SIZE(ppmu_events)) {
			dev_warn(dev,
				"don't know how to configure events : %pOFn\n",
				node);
			continue;
		}

		switch (info->ppmu_type) {
		case EXYNOS_TYPE_PPMU:
			desc[j].ops = &exynos_ppmu_ops;
			break;
		case EXYNOS_TYPE_PPMU_V2:
			desc[j].ops = &exynos_ppmu_v2_ops;
			break;
		}

		desc[j].driver_data = info;

		of_property_read_string(node, "event-name", &desc[j].name);
		ret = of_property_read_u32(node, "event-data-type",
					   &desc[j].event_type);
		if (ret) {
			/* Set the event of proper data type counting.
			 * Check if the data type has been defined in DT,
			 * use default if not.
			 */
			if (info->ppmu_type == EXYNOS_TYPE_PPMU_V2) {
				/* Not all registers take the same value for
				 * read+write data count.
				 */
				switch (ppmu_events[i].id) {
				case PPMU_PMNCNT0:
				case PPMU_PMNCNT1:
				case PPMU_PMNCNT2:
					desc[j].event_type = PPMU_V2_RO_DATA_CNT
						| PPMU_V2_WO_DATA_CNT;
					break;
				case PPMU_PMNCNT3:
					desc[j].event_type =
						PPMU_V2_EVT3_RW_DATA_CNT;
					break;
				}
			} else {
				desc[j].event_type = PPMU_RO_DATA_CNT |
					PPMU_WO_DATA_CNT;
			}
		}

		j++;
	}
	info->desc = desc;

	of_node_put(events_np);

	return 0;
}