int inv_mpu_core_probe()

in imu/inv_mpu6050/inv_mpu_core.c [1435:1646]


int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name,
		int (*inv_mpu_bus_setup)(struct iio_dev *), int chip_type)
{
	struct inv_mpu6050_state *st;
	struct iio_dev *indio_dev;
	struct inv_mpu6050_platform_data *pdata;
	struct device *dev = regmap_get_device(regmap);
	int result;
	struct irq_data *desc;
	int irq_type;

	indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
	if (!indio_dev)
		return -ENOMEM;

	BUILD_BUG_ON(ARRAY_SIZE(hw_info) != INV_NUM_PARTS);
	if (chip_type < 0 || chip_type >= INV_NUM_PARTS) {
		dev_err(dev, "Bad invensense chip_type=%d name=%s\n",
				chip_type, name);
		return -ENODEV;
	}
	st = iio_priv(indio_dev);
	mutex_init(&st->lock);
	st->chip_type = chip_type;
	st->irq = irq;
	st->map = regmap;

	pdata = dev_get_platdata(dev);
	if (!pdata) {
		result = iio_read_mount_matrix(dev, &st->orientation);
		if (result) {
			dev_err(dev, "Failed to retrieve mounting matrix %d\n",
				result);
			return result;
		}
	} else {
		st->plat_data = *pdata;
	}

	if (irq > 0) {
		desc = irq_get_irq_data(irq);
		if (!desc) {
			dev_err(dev, "Could not find IRQ %d\n", irq);
			return -EINVAL;
		}

		irq_type = irqd_get_trigger_type(desc);
		if (!irq_type)
			irq_type = IRQF_TRIGGER_RISING;
	} else {
		/* Doesn't really matter, use the default */
		irq_type = IRQF_TRIGGER_RISING;
	}

	if (irq_type & IRQF_TRIGGER_RISING)	// rising or both-edge
		st->irq_mask = INV_MPU6050_ACTIVE_HIGH;
	else if (irq_type == IRQF_TRIGGER_FALLING)
		st->irq_mask = INV_MPU6050_ACTIVE_LOW;
	else if (irq_type == IRQF_TRIGGER_HIGH)
		st->irq_mask = INV_MPU6050_ACTIVE_HIGH |
			INV_MPU6050_LATCH_INT_EN;
	else if (irq_type == IRQF_TRIGGER_LOW)
		st->irq_mask = INV_MPU6050_ACTIVE_LOW |
			INV_MPU6050_LATCH_INT_EN;
	else {
		dev_err(dev, "Invalid interrupt type 0x%x specified\n",
			irq_type);
		return -EINVAL;
	}

	st->vdd_supply = devm_regulator_get(dev, "vdd");
	if (IS_ERR(st->vdd_supply))
		return dev_err_probe(dev, PTR_ERR(st->vdd_supply),
				     "Failed to get vdd regulator\n");

	st->vddio_supply = devm_regulator_get(dev, "vddio");
	if (IS_ERR(st->vddio_supply))
		return dev_err_probe(dev, PTR_ERR(st->vddio_supply),
				     "Failed to get vddio regulator\n");

	result = regulator_enable(st->vdd_supply);
	if (result) {
		dev_err(dev, "Failed to enable vdd regulator: %d\n", result);
		return result;
	}
	msleep(INV_MPU6050_POWER_UP_TIME);

	result = inv_mpu_core_enable_regulator_vddio(st);
	if (result) {
		regulator_disable(st->vdd_supply);
		return result;
	}

	result = devm_add_action_or_reset(dev, inv_mpu_core_disable_regulator_action,
				 st);
	if (result) {
		dev_err(dev, "Failed to setup regulator cleanup action %d\n",
			result);
		return result;
	}

	/* fill magnetometer orientation */
	result = inv_mpu_magn_set_orient(st);
	if (result)
		return result;

	/* power is turned on inside check chip type*/
	result = inv_check_and_setup_chip(st);
	if (result)
		return result;

	result = inv_mpu6050_init_config(indio_dev);
	if (result) {
		dev_err(dev, "Could not initialize device.\n");
		goto error_power_off;
	}

	dev_set_drvdata(dev, indio_dev);
	/* name will be NULL when enumerated via ACPI */
	if (name)
		indio_dev->name = name;
	else
		indio_dev->name = dev_name(dev);

	/* requires parent device set in indio_dev */
	if (inv_mpu_bus_setup) {
		result = inv_mpu_bus_setup(indio_dev);
		if (result)
			goto error_power_off;
	}

	/* chip init is done, turning on runtime power management */
	result = pm_runtime_set_active(dev);
	if (result)
		goto error_power_off;
	pm_runtime_get_noresume(dev);
	pm_runtime_enable(dev);
	pm_runtime_set_autosuspend_delay(dev, INV_MPU6050_SUSPEND_DELAY_MS);
	pm_runtime_use_autosuspend(dev);
	pm_runtime_put(dev);
	result = devm_add_action_or_reset(dev, inv_mpu_pm_disable, dev);
	if (result)
		return result;

	switch (chip_type) {
	case INV_MPU9150:
		indio_dev->channels = inv_mpu9150_channels;
		indio_dev->num_channels = ARRAY_SIZE(inv_mpu9150_channels);
		indio_dev->available_scan_masks = inv_mpu9x50_scan_masks;
		break;
	case INV_MPU9250:
	case INV_MPU9255:
		indio_dev->channels = inv_mpu9250_channels;
		indio_dev->num_channels = ARRAY_SIZE(inv_mpu9250_channels);
		indio_dev->available_scan_masks = inv_mpu9x50_scan_masks;
		break;
	case INV_ICM20602:
		indio_dev->channels = inv_mpu_channels;
		indio_dev->num_channels = ARRAY_SIZE(inv_mpu_channels);
		indio_dev->available_scan_masks = inv_icm20602_scan_masks;
		break;
	default:
		indio_dev->channels = inv_mpu_channels;
		indio_dev->num_channels = ARRAY_SIZE(inv_mpu_channels);
		indio_dev->available_scan_masks = inv_mpu_scan_masks;
		break;
	}
	/*
	 * Use magnetometer inside the chip only if there is no i2c
	 * auxiliary device in use. Otherwise Going back to 6-axis only.
	 */
	if (st->magn_disabled) {
		indio_dev->channels = inv_mpu_channels;
		indio_dev->num_channels = ARRAY_SIZE(inv_mpu_channels);
		indio_dev->available_scan_masks = inv_mpu_scan_masks;
	}

	indio_dev->info = &mpu_info;

	if (irq > 0) {
		/*
		 * The driver currently only supports buffered capture with its
		 * own trigger. So no IRQ, no trigger, no buffer
		 */
		result = devm_iio_triggered_buffer_setup(dev, indio_dev,
							 iio_pollfunc_store_time,
							 inv_mpu6050_read_fifo,
							 NULL);
		if (result) {
			dev_err(dev, "configure buffer fail %d\n", result);
			return result;
		}

		result = inv_mpu6050_probe_trigger(indio_dev, irq_type);
		if (result) {
			dev_err(dev, "trigger probe fail %d\n", result);
			return result;
		}
	}

	result = devm_iio_device_register(dev, indio_dev);
	if (result) {
		dev_err(dev, "IIO register fail %d\n", result);
		return result;
	}

	return 0;

error_power_off:
	inv_mpu6050_set_power_itg(st, false);
	return result;
}