static int iqs269_parse_chan()

in misc/iqs269a.c [501:748]


static int iqs269_parse_chan(struct iqs269_private *iqs269,
			     const struct fwnode_handle *ch_node)
{
	struct i2c_client *client = iqs269->client;
	struct fwnode_handle *ev_node;
	struct iqs269_ch_reg *ch_reg;
	u16 engine_a, engine_b;
	unsigned int reg, val;
	int error, i;

	error = fwnode_property_read_u32(ch_node, "reg", &reg);
	if (error) {
		dev_err(&client->dev, "Failed to read channel number: %d\n",
			error);
		return error;
	} else if (reg >= IQS269_NUM_CH) {
		dev_err(&client->dev, "Invalid channel number: %u\n", reg);
		return -EINVAL;
	}

	iqs269->sys_reg.active |= BIT(reg);
	if (!fwnode_property_present(ch_node, "azoteq,reseed-disable"))
		iqs269->sys_reg.reseed |= BIT(reg);

	if (fwnode_property_present(ch_node, "azoteq,blocking-enable"))
		iqs269->sys_reg.blocking |= BIT(reg);

	if (fwnode_property_present(ch_node, "azoteq,slider0-select"))
		iqs269->sys_reg.slider_select[0] |= BIT(reg);

	if (fwnode_property_present(ch_node, "azoteq,slider1-select"))
		iqs269->sys_reg.slider_select[1] |= BIT(reg);

	ch_reg = &iqs269->ch_reg[reg];

	error = regmap_raw_read(iqs269->regmap,
				IQS269_CHx_SETTINGS + reg * sizeof(*ch_reg) / 2,
				ch_reg, sizeof(*ch_reg));
	if (error)
		return error;

	error = iqs269_parse_mask(ch_node, "azoteq,rx-enable",
				  &ch_reg->rx_enable);
	if (error) {
		dev_err(&client->dev, "Invalid channel %u RX enable mask: %d\n",
			reg, error);
		return error;
	}

	error = iqs269_parse_mask(ch_node, "azoteq,tx-enable",
				  &ch_reg->tx_enable);
	if (error) {
		dev_err(&client->dev, "Invalid channel %u TX enable mask: %d\n",
			reg, error);
		return error;
	}

	engine_a = be16_to_cpu(ch_reg->engine_a);
	engine_b = be16_to_cpu(ch_reg->engine_b);

	engine_a |= IQS269_CHx_ENG_A_MEAS_CAP_SIZE;
	if (fwnode_property_present(ch_node, "azoteq,meas-cap-decrease"))
		engine_a &= ~IQS269_CHx_ENG_A_MEAS_CAP_SIZE;

	engine_a |= IQS269_CHx_ENG_A_RX_GND_INACTIVE;
	if (fwnode_property_present(ch_node, "azoteq,rx-float-inactive"))
		engine_a &= ~IQS269_CHx_ENG_A_RX_GND_INACTIVE;

	engine_a &= ~IQS269_CHx_ENG_A_LOCAL_CAP_SIZE;
	engine_b &= ~IQS269_CHx_ENG_B_LOCAL_CAP_ENABLE;
	if (!fwnode_property_read_u32(ch_node, "azoteq,local-cap-size", &val)) {
		switch (val) {
		case IQS269_LOCAL_CAP_SIZE_0:
			break;

		case IQS269_LOCAL_CAP_SIZE_GLOBAL_0pF5:
			engine_a |= IQS269_CHx_ENG_A_LOCAL_CAP_SIZE;
			fallthrough;

		case IQS269_LOCAL_CAP_SIZE_GLOBAL_ONLY:
			engine_b |= IQS269_CHx_ENG_B_LOCAL_CAP_ENABLE;
			break;

		default:
			dev_err(&client->dev,
				"Invalid channel %u local cap. size: %u\n", reg,
				val);
			return -EINVAL;
		}
	}

	engine_a &= ~IQS269_CHx_ENG_A_INV_LOGIC;
	if (fwnode_property_present(ch_node, "azoteq,invert-enable"))
		engine_a |= IQS269_CHx_ENG_A_INV_LOGIC;

	if (!fwnode_property_read_u32(ch_node, "azoteq,proj-bias", &val)) {
		if (val > IQS269_CHx_ENG_A_PROJ_BIAS_MAX) {
			dev_err(&client->dev,
				"Invalid channel %u bias current: %u\n", reg,
				val);
			return -EINVAL;
		}

		engine_a &= ~IQS269_CHx_ENG_A_PROJ_BIAS_MASK;
		engine_a |= (val << IQS269_CHx_ENG_A_PROJ_BIAS_SHIFT);
	}

	if (!fwnode_property_read_u32(ch_node, "azoteq,sense-mode", &val)) {
		if (val > IQS269_CHx_ENG_A_SENSE_MODE_MAX) {
			dev_err(&client->dev,
				"Invalid channel %u sensing mode: %u\n", reg,
				val);
			return -EINVAL;
		}

		engine_a &= ~IQS269_CHx_ENG_A_SENSE_MODE_MASK;
		engine_a |= val;
	}

	if (!fwnode_property_read_u32(ch_node, "azoteq,sense-freq", &val)) {
		if (val > IQS269_CHx_ENG_B_SENSE_FREQ_MAX) {
			dev_err(&client->dev,
				"Invalid channel %u sensing frequency: %u\n",
				reg, val);
			return -EINVAL;
		}

		engine_b &= ~IQS269_CHx_ENG_B_SENSE_FREQ_MASK;
		engine_b |= (val << IQS269_CHx_ENG_B_SENSE_FREQ_SHIFT);
	}

	engine_b &= ~IQS269_CHx_ENG_B_STATIC_ENABLE;
	if (fwnode_property_present(ch_node, "azoteq,static-enable"))
		engine_b |= IQS269_CHx_ENG_B_STATIC_ENABLE;

	ch_reg->engine_a = cpu_to_be16(engine_a);
	ch_reg->engine_b = cpu_to_be16(engine_b);

	if (!fwnode_property_read_u32(ch_node, "azoteq,ati-mode", &val)) {
		error = iqs269_ati_mode_set(iqs269, reg, val);
		if (error) {
			dev_err(&client->dev,
				"Invalid channel %u ATI mode: %u\n", reg, val);
			return error;
		}
	}

	if (!fwnode_property_read_u32(ch_node, "azoteq,ati-base", &val)) {
		error = iqs269_ati_base_set(iqs269, reg, val);
		if (error) {
			dev_err(&client->dev,
				"Invalid channel %u ATI base: %u\n", reg, val);
			return error;
		}
	}

	if (!fwnode_property_read_u32(ch_node, "azoteq,ati-target", &val)) {
		error = iqs269_ati_target_set(iqs269, reg, val);
		if (error) {
			dev_err(&client->dev,
				"Invalid channel %u ATI target: %u\n", reg,
				val);
			return error;
		}
	}

	error = iqs269_parse_mask(ch_node, "azoteq,assoc-select",
				  &ch_reg->assoc_select);
	if (error) {
		dev_err(&client->dev, "Invalid channel %u association: %d\n",
			reg, error);
		return error;
	}

	if (!fwnode_property_read_u32(ch_node, "azoteq,assoc-weight", &val)) {
		if (val > IQS269_CHx_WEIGHT_MAX) {
			dev_err(&client->dev,
				"Invalid channel %u associated weight: %u\n",
				reg, val);
			return -EINVAL;
		}

		ch_reg->assoc_weight = val;
	}

	for (i = 0; i < ARRAY_SIZE(iqs269_events); i++) {
		ev_node = fwnode_get_named_child_node(ch_node,
						      iqs269_events[i].name);
		if (!ev_node)
			continue;

		if (!fwnode_property_read_u32(ev_node, "azoteq,thresh", &val)) {
			if (val > IQS269_CHx_THRESH_MAX) {
				dev_err(&client->dev,
					"Invalid channel %u threshold: %u\n",
					reg, val);
				return -EINVAL;
			}

			ch_reg->thresh[iqs269_events[i].th_offs] = val;
		}

		if (!fwnode_property_read_u32(ev_node, "azoteq,hyst", &val)) {
			u8 *hyst = &ch_reg->hyst;

			if (val > IQS269_CHx_HYST_MAX) {
				dev_err(&client->dev,
					"Invalid channel %u hysteresis: %u\n",
					reg, val);
				return -EINVAL;
			}

			if (i == IQS269_EVENT_DEEP_DN ||
			    i == IQS269_EVENT_DEEP_UP) {
				*hyst &= ~IQS269_CHx_HYST_DEEP_MASK;
				*hyst |= (val << IQS269_CHx_HYST_DEEP_SHIFT);
			} else if (i == IQS269_EVENT_TOUCH_DN ||
				   i == IQS269_EVENT_TOUCH_UP) {
				*hyst &= ~IQS269_CHx_HYST_TOUCH_MASK;
				*hyst |= val;
			}
		}

		if (fwnode_property_read_u32(ev_node, "linux,code", &val))
			continue;

		switch (reg) {
		case IQS269_CHx_HALL_ACTIVE:
			if (iqs269->hall_enable) {
				iqs269->switches[i].code = val;
				iqs269->switches[i].enabled = true;
			}
			fallthrough;

		case IQS269_CHx_HALL_INACTIVE:
			if (iqs269->hall_enable)
				break;
			fallthrough;

		default:
			iqs269->keycode[i * IQS269_NUM_CH + reg] = val;
		}

		iqs269->sys_reg.event_mask &= ~iqs269_events[i].mask;
	}

	return 0;
}