drivers/extcon/extcon-adc-jack.c

Source file repositories/reference/linux-study-clean/drivers/extcon/extcon-adc-jack.c

File Facts

System
Linux kernel
Corpus path
drivers/extcon/extcon-adc-jack.c
Extension
.c
Size
5558 bytes
Lines
213
Domain
Driver Families
Bucket
drivers/extcon
Inferred role
Driver Families: implementation source
Status
source 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

struct adc_jack_data {
	struct device *dev;
	struct extcon_dev *edev;

	const unsigned int **cable_names;
	struct adc_jack_cond *adc_conditions;
	int num_conditions;

	int irq;
	unsigned long handling_delay; /* in jiffies */
	struct delayed_work handler;

	struct iio_channel *chan;
	bool wakeup_source;
};

static void adc_jack_handler(struct work_struct *work)
{
	struct adc_jack_data *data = container_of(to_delayed_work(work),
			struct adc_jack_data,
			handler);
	struct adc_jack_cond *def;
	int ret, adc_val;
	int i;

	ret = iio_read_channel_raw(data->chan, &adc_val);
	if (ret < 0) {
		dev_err(data->dev, "read channel() error: %d\n", ret);
		return;
	}

	/* Get state from adc value with adc_conditions */
	for (i = 0; i < data->num_conditions; i++) {
		def = &data->adc_conditions[i];
		if (def->min_adc <= adc_val && def->max_adc >= adc_val) {
			extcon_set_state_sync(data->edev, def->id, true);
			return;
		}
	}

	/* Set the detached state if adc value is not included in the range */
	for (i = 0; i < data->num_conditions; i++) {
		def = &data->adc_conditions[i];
		extcon_set_state_sync(data->edev, def->id, false);
	}
}

static irqreturn_t adc_jack_irq_thread(int irq, void *_data)
{
	struct adc_jack_data *data = _data;

	queue_delayed_work(system_power_efficient_wq,
			   &data->handler, data->handling_delay);
	return IRQ_HANDLED;
}

static int adc_jack_probe(struct platform_device *pdev)
{
	struct adc_jack_data *data;
	struct adc_jack_pdata *pdata = dev_get_platdata(&pdev->dev);
	int i, err = 0;

	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
	if (!data)
		return -ENOMEM;

	if (!pdata->cable_names) {
		dev_err(&pdev->dev, "error: cable_names not defined.\n");
		return -EINVAL;
	}

	data->dev = &pdev->dev;
	data->edev = devm_extcon_dev_allocate(&pdev->dev, pdata->cable_names);
	if (IS_ERR(data->edev)) {
		dev_err(&pdev->dev, "failed to allocate extcon device\n");
		return -ENOMEM;
	}

	if (!pdata->adc_conditions) {
		dev_err(&pdev->dev, "error: adc_conditions not defined.\n");
		return -EINVAL;
	}
	data->adc_conditions = pdata->adc_conditions;

	/* Check the length of array and set num_conditions */
	for (i = 0; data->adc_conditions[i].id != EXTCON_NONE; i++);
	data->num_conditions = i;

	data->chan = devm_iio_channel_get(&pdev->dev, pdata->consumer_channel);
	if (IS_ERR(data->chan))

Annotation

Implementation Notes