drivers/mfd/ti_am335x_tscadc.c

Source file repositories/reference/linux-study-clean/drivers/mfd/ti_am335x_tscadc.c

File Facts

System
Linux kernel
Corpus path
drivers/mfd/ti_am335x_tscadc.c
Extension
.c
Size
10384 bytes
Lines
389
Domain
Driver Families
Bucket
drivers/mfd
Inferred role
Driver Families: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

if (val > 7) {
			dev_err(&pdev->dev, " PIN numbers are 0..7 (not %d)\n",
				val);
			of_node_put(node);
			return -EINVAL;
		}
	}

	of_node_put(node);

	total_channels = tscmag_wires + adc_channels;
	if (total_channels > 8) {
		dev_err(&pdev->dev, "Number of i/p channels more than 8\n");
		return -EINVAL;
	}

	if (total_channels == 0) {
		dev_err(&pdev->dev, "Need at least one channel.\n");
		return -EINVAL;
	}

	if (use_tsc && (readouts * 2 + 2 + adc_channels > 16)) {
		dev_err(&pdev->dev, "Too many step configurations requested\n");
		return -EINVAL;
	}

	err = platform_get_irq(pdev, 0);
	if (err < 0)
		return err;
	else
		tscadc->irq = err;

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

	tscadc->tscadc_phys_base = res->start;
	tscadc->regmap = devm_regmap_init_mmio(&pdev->dev,
					       tscadc->tscadc_base,
					       &tscadc_regmap_config);
	if (IS_ERR(tscadc->regmap)) {
		dev_err(&pdev->dev, "regmap init failed\n");
		return PTR_ERR(tscadc->regmap);
	}

	spin_lock_init(&tscadc->reg_lock);
	init_waitqueue_head(&tscadc->reg_se_wait);

	pm_runtime_enable(&pdev->dev);
	pm_runtime_get_sync(&pdev->dev);

	/*
	 * The TSC_ADC_Subsystem has 2 clock domains: OCP_CLK and ADC_CLK.
	 * ADCs produce a 12-bit sample every 15 ADC_CLK cycles.
	 * am33xx ADCs expect to capture 200ksps.
	 * am47xx ADCs expect to capture 867ksps.
	 * We need ADC clocks respectively running at 3MHz and 13MHz.
	 * These frequencies are valid since TSC_ADC_SS controller design
	 * assumes the OCP clock is at least 6x faster than the ADC clock.
	 */
	clk = devm_clk_get(&pdev->dev, NULL);
	if (IS_ERR(clk)) {
		dev_err(&pdev->dev, "failed to get fck\n");
		err = PTR_ERR(clk);
		goto err_disable_clk;
	}

	tscadc->clk_div = (clk_get_rate(clk) / tscadc->data->target_clk_rate) - 1;
	regmap_write(tscadc->regmap, REG_CLKDIV, tscadc->clk_div);

	/*
	 * Set the control register bits. tscadc->ctrl stores the configuration
	 * of the CTRL register but not the subsystem enable bit which must be
	 * added manually when timely.
	 */
	tscadc->ctrl = CNTRLREG_STEPID;
	if (ti_adc_with_touchscreen(tscadc)) {
		tscadc->ctrl |= CNTRLREG_TSC_STEPCONFIGWRT;
		if (use_tsc) {
			tscadc->ctrl |= CNTRLREG_TSC_ENB;
			if (tscmag_wires == 5)
				tscadc->ctrl |= CNTRLREG_TSC_5WIRE;
			else
				tscadc->ctrl |= CNTRLREG_TSC_4WIRE;
		}
	} else {
		tscadc->ctrl |= CNTRLREG_MAG_PREAMP_PWRDOWN |
				CNTRLREG_MAG_PREAMP_BYPASS;
	}
	regmap_write(tscadc->regmap, REG_CTRL, tscadc->ctrl);

Annotation

Implementation Notes