static int at91_adc_probe()

in adc/at91-sama5d2_adc.c [1921:2087]


static int at91_adc_probe(struct platform_device *pdev)
{
	struct iio_dev *indio_dev;
	struct at91_adc_state *st;
	struct resource	*res;
	int ret, i;
	u32 edge_type = IRQ_TYPE_NONE;

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

	st = iio_priv(indio_dev);
	st->indio_dev = indio_dev;

	st->soc_info.platform = of_device_get_match_data(&pdev->dev);

	indio_dev->name = dev_name(&pdev->dev);
	indio_dev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE;
	indio_dev->info = &at91_adc_info;
	indio_dev->channels = *st->soc_info.platform->adc_channels;
	indio_dev->num_channels = st->soc_info.platform->max_channels;

	bitmap_set(&st->touch_st.channels_bitmask,
		   st->soc_info.platform->touch_chan_x, 1);
	bitmap_set(&st->touch_st.channels_bitmask,
		   st->soc_info.platform->touch_chan_y, 1);
	bitmap_set(&st->touch_st.channels_bitmask,
		   st->soc_info.platform->touch_chan_p, 1);

	st->oversampling_ratio = AT91_OSR_1SAMPLES;

	ret = of_property_read_u32(pdev->dev.of_node,
				   "atmel,min-sample-rate-hz",
				   &st->soc_info.min_sample_rate);
	if (ret) {
		dev_err(&pdev->dev,
			"invalid or missing value for atmel,min-sample-rate-hz\n");
		return ret;
	}

	ret = of_property_read_u32(pdev->dev.of_node,
				   "atmel,max-sample-rate-hz",
				   &st->soc_info.max_sample_rate);
	if (ret) {
		dev_err(&pdev->dev,
			"invalid or missing value for atmel,max-sample-rate-hz\n");
		return ret;
	}

	ret = of_property_read_u32(pdev->dev.of_node, "atmel,startup-time-ms",
				   &st->soc_info.startup_time);
	if (ret) {
		dev_err(&pdev->dev,
			"invalid or missing value for atmel,startup-time-ms\n");
		return ret;
	}

	ret = of_property_read_u32(pdev->dev.of_node,
				   "atmel,trigger-edge-type", &edge_type);
	if (ret) {
		dev_dbg(&pdev->dev,
			"atmel,trigger-edge-type not specified, only software trigger available\n");
	}

	st->selected_trig = NULL;

	/* find the right trigger, or no trigger at all */
	for (i = 0; i < st->soc_info.platform->hw_trig_cnt + 1; i++)
		if (at91_adc_trigger_list[i].edge_type == edge_type) {
			st->selected_trig = &at91_adc_trigger_list[i];
			break;
		}

	if (!st->selected_trig) {
		dev_err(&pdev->dev, "invalid external trigger edge value\n");
		return -EINVAL;
	}

	init_waitqueue_head(&st->wq_data_available);
	mutex_init(&st->lock);
	INIT_WORK(&st->touch_st.workq, at91_adc_workq_handler);

	st->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
	if (IS_ERR(st->base))
		return PTR_ERR(st->base);

	/* if we plan to use DMA, we need the physical address of the regs */
	st->dma_st.phys_addr = res->start;

	st->irq = platform_get_irq(pdev, 0);
	if (st->irq <= 0) {
		if (!st->irq)
			st->irq = -ENXIO;

		return st->irq;
	}

	st->per_clk = devm_clk_get(&pdev->dev, "adc_clk");
	if (IS_ERR(st->per_clk))
		return PTR_ERR(st->per_clk);

	st->reg = devm_regulator_get(&pdev->dev, "vddana");
	if (IS_ERR(st->reg))
		return PTR_ERR(st->reg);

	st->vref = devm_regulator_get(&pdev->dev, "vref");
	if (IS_ERR(st->vref))
		return PTR_ERR(st->vref);

	ret = devm_request_irq(&pdev->dev, st->irq, at91_adc_interrupt, 0,
			       pdev->dev.driver->name, indio_dev);
	if (ret)
		return ret;

	ret = regulator_enable(st->reg);
	if (ret)
		return ret;

	ret = regulator_enable(st->vref);
	if (ret)
		goto reg_disable;

	st->vref_uv = regulator_get_voltage(st->vref);
	if (st->vref_uv <= 0) {
		ret = -EINVAL;
		goto vref_disable;
	}

	ret = clk_prepare_enable(st->per_clk);
	if (ret)
		goto vref_disable;

	at91_adc_hw_init(indio_dev);

	platform_set_drvdata(pdev, indio_dev);

	ret = at91_adc_buffer_and_trigger_init(&pdev->dev, indio_dev);
	if (ret < 0)
		goto per_clk_disable_unprepare;

	if (dma_coerce_mask_and_coherent(&indio_dev->dev, DMA_BIT_MASK(32)))
		dev_info(&pdev->dev, "cannot set DMA mask to 32-bit\n");

	ret = iio_device_register(indio_dev);
	if (ret < 0)
		goto dma_disable;

	if (st->selected_trig->hw_trig)
		dev_info(&pdev->dev, "setting up trigger as %s\n",
			 st->selected_trig->name);

	dev_info(&pdev->dev, "version: %x\n",
		 readl_relaxed(st->base + st->soc_info.platform->layout->VERSION));

	return 0;

dma_disable:
	at91_adc_dma_disable(st);
per_clk_disable_unprepare:
	clk_disable_unprepare(st->per_clk);
vref_disable:
	regulator_disable(st->vref);
reg_disable:
	regulator_disable(st->reg);
	return ret;
}