static int ad3552r_configure_device()

in dac/ad3552r.c [880:1028]


static int ad3552r_configure_device(struct ad3552r_desc *dac)
{
	struct device *dev = &dac->spi->dev;
	struct fwnode_handle *child;
	struct regulator *vref;
	int err, cnt = 0, voltage, delta = 100000;
	u32 vals[2], val, ch;

	dac->gpio_ldac = devm_gpiod_get_optional(dev, "ldac", GPIOD_OUT_HIGH);
	if (IS_ERR(dac->gpio_ldac))
		return dev_err_probe(dev, PTR_ERR(dac->gpio_ldac),
				     "Error getting gpio ldac");

	vref = devm_regulator_get_optional(dev, "vref");
	if (IS_ERR(vref)) {
		if (PTR_ERR(vref) != -ENODEV)
			return dev_err_probe(dev, PTR_ERR(vref),
					     "Error getting vref");

		if (device_property_read_bool(dev, "adi,vref-out-en"))
			val = AD3552R_INTERNAL_VREF_PIN_2P5V;
		else
			val = AD3552R_INTERNAL_VREF_PIN_FLOATING;
	} else {
		err = regulator_enable(vref);
		if (err) {
			dev_err(dev, "Failed to enable external vref supply\n");
			return err;
		}

		err = devm_add_action_or_reset(dev, ad3552r_reg_disable, vref);
		if (err) {
			regulator_disable(vref);
			return err;
		}

		voltage = regulator_get_voltage(vref);
		if (voltage > 2500000 + delta || voltage < 2500000 - delta) {
			dev_warn(dev, "vref-supply must be 2.5V");
			return -EINVAL;
		}
		val = AD3552R_EXTERNAL_VREF_PIN_INPUT;
	}

	err = ad3552r_update_reg_field(dac,
				       addr_mask_map[AD3552R_VREF_SELECT][0],
				       addr_mask_map[AD3552R_VREF_SELECT][1],
				       val);
	if (err)
		return err;

	err = device_property_read_u32(dev, "adi,sdo-drive-strength", &val);
	if (!err) {
		if (val > 3) {
			dev_err(dev, "adi,sdo-drive-strength must be less than 4\n");
			return -EINVAL;
		}

		err = ad3552r_update_reg_field(dac,
					       addr_mask_map[AD3552R_SDO_DRIVE_STRENGTH][0],
					       addr_mask_map[AD3552R_SDO_DRIVE_STRENGTH][1],
					       val);
		if (err)
			return err;
	}

	dac->num_ch = device_get_child_node_count(dev);
	if (!dac->num_ch) {
		dev_err(dev, "No channels defined\n");
		return -ENODEV;
	}

	device_for_each_child_node(dev, child) {
		err = fwnode_property_read_u32(child, "reg", &ch);
		if (err) {
			dev_err(dev, "mandatory reg property missing\n");
			goto put_child;
		}
		if (ch >= AD3552R_NUM_CH) {
			dev_err(dev, "reg must be less than %d\n",
				AD3552R_NUM_CH);
			err = -EINVAL;
			goto put_child;
		}

		if (fwnode_property_present(child, "adi,output-range-microvolt")) {
			err = fwnode_property_read_u32_array(child,
							     "adi,output-range-microvolt",
							     vals,
							     2);
			if (err) {
				dev_err(dev,
					"adi,output-range-microvolt property could not be parsed\n");
				goto put_child;
			}

			err = ad3552r_find_range(dac->chip_id, vals);
			if (err < 0) {
				dev_err(dev,
					"Invalid adi,output-range-microvolt value\n");
				goto put_child;
			}
			val = err;
			err = ad3552r_set_ch_value(dac,
						   AD3552R_CH_OUTPUT_RANGE_SEL,
						   ch, val);
			if (err)
				goto put_child;

			dac->ch_data[ch].range = val;
		} else if (dac->chip_id == AD3542R_ID) {
			dev_err(dev,
				"adi,output-range-microvolt is required for ad3542r\n");
			err = -EINVAL;
			goto put_child;
		} else {
			err = ad3552r_configure_custom_gain(dac, child, ch);
			if (err)
				goto put_child;
		}

		ad3552r_calc_gain_and_offset(dac, ch);
		dac->enabled_ch |= BIT(ch);

		err = ad3552r_set_ch_value(dac, AD3552R_CH_SELECT, ch, 1);
		if (err < 0)
			goto put_child;

		dac->channels[cnt] = AD3552R_CH_DAC(ch);
		++cnt;

	}

	/* Disable unused channels */
	for_each_clear_bit(ch, &dac->enabled_ch, AD3552R_NUM_CH) {
		err = ad3552r_set_ch_value(dac, AD3552R_CH_AMPLIFIER_POWERDOWN,
					   ch, 1);
		if (err)
			return err;
	}

	dac->num_ch = cnt;

	return 0;
put_child:
	fwnode_handle_put(child);

	return err;
}