static int iqs269_parse_prop()

in misc/iqs269a.c [750:1031]


static int iqs269_parse_prop(struct iqs269_private *iqs269)
{
	struct iqs269_sys_reg *sys_reg = &iqs269->sys_reg;
	struct i2c_client *client = iqs269->client;
	struct fwnode_handle *ch_node;
	u16 general, misc_a, misc_b;
	unsigned int val;
	int error;

	iqs269->hall_enable = device_property_present(&client->dev,
						      "azoteq,hall-enable");

	if (!device_property_read_u32(&client->dev, "azoteq,suspend-mode",
				      &val)) {
		if (val > IQS269_SYS_SETTINGS_PWR_MODE_MAX) {
			dev_err(&client->dev, "Invalid suspend mode: %u\n",
				val);
			return -EINVAL;
		}

		iqs269->suspend_mode = val;
	}

	error = regmap_raw_read(iqs269->regmap, IQS269_SYS_SETTINGS, sys_reg,
				sizeof(*sys_reg));
	if (error)
		return error;

	if (!device_property_read_u32(&client->dev, "azoteq,filt-str-lp-lta",
				      &val)) {
		if (val > IQS269_FILT_STR_MAX) {
			dev_err(&client->dev, "Invalid filter strength: %u\n",
				val);
			return -EINVAL;
		}

		sys_reg->filter &= ~IQS269_FILT_STR_LP_LTA_MASK;
		sys_reg->filter |= (val << IQS269_FILT_STR_LP_LTA_SHIFT);
	}

	if (!device_property_read_u32(&client->dev, "azoteq,filt-str-lp-cnt",
				      &val)) {
		if (val > IQS269_FILT_STR_MAX) {
			dev_err(&client->dev, "Invalid filter strength: %u\n",
				val);
			return -EINVAL;
		}

		sys_reg->filter &= ~IQS269_FILT_STR_LP_CNT_MASK;
		sys_reg->filter |= (val << IQS269_FILT_STR_LP_CNT_SHIFT);
	}

	if (!device_property_read_u32(&client->dev, "azoteq,filt-str-np-lta",
				      &val)) {
		if (val > IQS269_FILT_STR_MAX) {
			dev_err(&client->dev, "Invalid filter strength: %u\n",
				val);
			return -EINVAL;
		}

		sys_reg->filter &= ~IQS269_FILT_STR_NP_LTA_MASK;
		sys_reg->filter |= (val << IQS269_FILT_STR_NP_LTA_SHIFT);
	}

	if (!device_property_read_u32(&client->dev, "azoteq,filt-str-np-cnt",
				      &val)) {
		if (val > IQS269_FILT_STR_MAX) {
			dev_err(&client->dev, "Invalid filter strength: %u\n",
				val);
			return -EINVAL;
		}

		sys_reg->filter &= ~IQS269_FILT_STR_NP_CNT_MASK;
		sys_reg->filter |= val;
	}

	if (!device_property_read_u32(&client->dev, "azoteq,rate-np-ms",
				      &val)) {
		if (val > IQS269_RATE_NP_MS_MAX) {
			dev_err(&client->dev, "Invalid report rate: %u\n", val);
			return -EINVAL;
		}

		sys_reg->rate_np = val;
	}

	if (!device_property_read_u32(&client->dev, "azoteq,rate-lp-ms",
				      &val)) {
		if (val > IQS269_RATE_LP_MS_MAX) {
			dev_err(&client->dev, "Invalid report rate: %u\n", val);
			return -EINVAL;
		}

		sys_reg->rate_lp = val;
	}

	if (!device_property_read_u32(&client->dev, "azoteq,rate-ulp-ms",
				      &val)) {
		if (val > IQS269_RATE_ULP_MS_MAX) {
			dev_err(&client->dev, "Invalid report rate: %u\n", val);
			return -EINVAL;
		}

		sys_reg->rate_ulp = val / 16;
	}

	if (!device_property_read_u32(&client->dev, "azoteq,timeout-pwr-ms",
				      &val)) {
		if (val > IQS269_TIMEOUT_PWR_MS_MAX) {
			dev_err(&client->dev, "Invalid timeout: %u\n", val);
			return -EINVAL;
		}

		sys_reg->timeout_pwr = val / 512;
	}

	if (!device_property_read_u32(&client->dev, "azoteq,timeout-lta-ms",
				      &val)) {
		if (val > IQS269_TIMEOUT_LTA_MS_MAX) {
			dev_err(&client->dev, "Invalid timeout: %u\n", val);
			return -EINVAL;
		}

		sys_reg->timeout_lta = val / 512;
	}

	misc_a = be16_to_cpu(sys_reg->misc_a);
	misc_b = be16_to_cpu(sys_reg->misc_b);

	misc_a &= ~IQS269_MISC_A_ATI_BAND_DISABLE;
	if (device_property_present(&client->dev, "azoteq,ati-band-disable"))
		misc_a |= IQS269_MISC_A_ATI_BAND_DISABLE;

	misc_a &= ~IQS269_MISC_A_ATI_LP_ONLY;
	if (device_property_present(&client->dev, "azoteq,ati-lp-only"))
		misc_a |= IQS269_MISC_A_ATI_LP_ONLY;

	misc_a &= ~IQS269_MISC_A_ATI_BAND_TIGHTEN;
	if (device_property_present(&client->dev, "azoteq,ati-band-tighten"))
		misc_a |= IQS269_MISC_A_ATI_BAND_TIGHTEN;

	misc_a &= ~IQS269_MISC_A_FILT_DISABLE;
	if (device_property_present(&client->dev, "azoteq,filt-disable"))
		misc_a |= IQS269_MISC_A_FILT_DISABLE;

	if (!device_property_read_u32(&client->dev, "azoteq,gpio3-select",
				      &val)) {
		if (val >= IQS269_NUM_CH) {
			dev_err(&client->dev, "Invalid GPIO3 selection: %u\n",
				val);
			return -EINVAL;
		}

		misc_a &= ~IQS269_MISC_A_GPIO3_SELECT_MASK;
		misc_a |= (val << IQS269_MISC_A_GPIO3_SELECT_SHIFT);
	}

	misc_a &= ~IQS269_MISC_A_DUAL_DIR;
	if (device_property_present(&client->dev, "azoteq,dual-direction"))
		misc_a |= IQS269_MISC_A_DUAL_DIR;

	if (!device_property_read_u32(&client->dev, "azoteq,tx-freq", &val)) {
		if (val > IQS269_MISC_A_TX_FREQ_MAX) {
			dev_err(&client->dev,
				"Invalid excitation frequency: %u\n", val);
			return -EINVAL;
		}

		misc_a &= ~IQS269_MISC_A_TX_FREQ_MASK;
		misc_a |= (val << IQS269_MISC_A_TX_FREQ_SHIFT);
	}

	misc_a &= ~IQS269_MISC_A_GLOBAL_CAP_SIZE;
	if (device_property_present(&client->dev, "azoteq,global-cap-increase"))
		misc_a |= IQS269_MISC_A_GLOBAL_CAP_SIZE;

	if (!device_property_read_u32(&client->dev, "azoteq,reseed-select",
				      &val)) {
		if (val > IQS269_MISC_B_RESEED_UI_SEL_MAX) {
			dev_err(&client->dev, "Invalid reseed selection: %u\n",
				val);
			return -EINVAL;
		}

		misc_b &= ~IQS269_MISC_B_RESEED_UI_SEL_MASK;
		misc_b |= (val << IQS269_MISC_B_RESEED_UI_SEL_SHIFT);
	}

	misc_b &= ~IQS269_MISC_B_TRACKING_UI_ENABLE;
	if (device_property_present(&client->dev, "azoteq,tracking-enable"))
		misc_b |= IQS269_MISC_B_TRACKING_UI_ENABLE;

	if (!device_property_read_u32(&client->dev, "azoteq,filt-str-slider",
				      &val)) {
		if (val > IQS269_FILT_STR_MAX) {
			dev_err(&client->dev, "Invalid filter strength: %u\n",
				val);
			return -EINVAL;
		}

		misc_b &= ~IQS269_MISC_B_FILT_STR_SLIDER;
		misc_b |= val;
	}

	sys_reg->misc_a = cpu_to_be16(misc_a);
	sys_reg->misc_b = cpu_to_be16(misc_b);

	sys_reg->active = 0;
	sys_reg->reseed = 0;

	sys_reg->blocking = 0;

	sys_reg->slider_select[0] = 0;
	sys_reg->slider_select[1] = 0;

	sys_reg->event_mask = ~((u8)IQS269_EVENT_MASK_SYS);

	device_for_each_child_node(&client->dev, ch_node) {
		error = iqs269_parse_chan(iqs269, ch_node);
		if (error) {
			fwnode_handle_put(ch_node);
			return error;
		}
	}

	/*
	 * Volunteer all active channels to participate in ATI when REDO-ATI is
	 * manually triggered.
	 */
	sys_reg->redo_ati = sys_reg->active;

	general = be16_to_cpu(sys_reg->general);

	if (device_property_present(&client->dev, "azoteq,clk-div")) {
		general |= IQS269_SYS_SETTINGS_CLK_DIV;
		iqs269->delay_mult = 4;
	} else {
		general &= ~IQS269_SYS_SETTINGS_CLK_DIV;
		iqs269->delay_mult = 1;
	}

	/*
	 * Configure the device to automatically switch between normal and low-
	 * power modes as a function of sensing activity. Ultra-low-power mode,
	 * if enabled, is reserved for suspend.
	 */
	general &= ~IQS269_SYS_SETTINGS_ULP_AUTO;
	general &= ~IQS269_SYS_SETTINGS_DIS_AUTO;
	general &= ~IQS269_SYS_SETTINGS_PWR_MODE_MASK;

	if (!device_property_read_u32(&client->dev, "azoteq,ulp-update",
				      &val)) {
		if (val > IQS269_SYS_SETTINGS_ULP_UPDATE_MAX) {
			dev_err(&client->dev, "Invalid update rate: %u\n", val);
			return -EINVAL;
		}

		general &= ~IQS269_SYS_SETTINGS_ULP_UPDATE_MASK;
		general |= (val << IQS269_SYS_SETTINGS_ULP_UPDATE_SHIFT);
	}

	general &= ~IQS269_SYS_SETTINGS_RESEED_OFFSET;
	if (device_property_present(&client->dev, "azoteq,reseed-offset"))
		general |= IQS269_SYS_SETTINGS_RESEED_OFFSET;

	general |= IQS269_SYS_SETTINGS_EVENT_MODE;

	/*
	 * As per the datasheet, enable streaming during normal-power mode if
	 * either slider is in use. In that case, the device returns to event
	 * mode during low-power mode.
	 */
	if (sys_reg->slider_select[0] || sys_reg->slider_select[1])
		general |= IQS269_SYS_SETTINGS_EVENT_MODE_LP;

	general |= IQS269_SYS_SETTINGS_REDO_ATI;
	general |= IQS269_SYS_SETTINGS_ACK_RESET;

	sys_reg->general = cpu_to_be16(general);

	return 0;
}