119939860Sanish kumar /* 219939860Sanish kumar * drivers/extcon/extcon-adc-jack.c 319939860Sanish kumar * 419939860Sanish kumar * Analog Jack extcon driver with ADC-based detection capability. 519939860Sanish kumar * 619939860Sanish kumar * Copyright (C) 2012 Samsung Electronics 719939860Sanish kumar * MyungJoo Ham <myungjoo.ham@samsung.com> 819939860Sanish kumar * 919939860Sanish kumar * Modified for calling to IIO to get adc by <anish.singh@samsung.com> 1019939860Sanish kumar * 1119939860Sanish kumar * This program is free software; you can redistribute it and/or modify 1219939860Sanish kumar * it under the terms of the GNU General Public License version 2 as 1319939860Sanish kumar * published by the Free Software Foundation. 1419939860Sanish kumar * 1519939860Sanish kumar */ 1619939860Sanish kumar 1719939860Sanish kumar #include <linux/slab.h> 1819939860Sanish kumar #include <linux/device.h> 1919939860Sanish kumar #include <linux/platform_device.h> 2019939860Sanish kumar #include <linux/err.h> 2119939860Sanish kumar #include <linux/interrupt.h> 2219939860Sanish kumar #include <linux/workqueue.h> 2319939860Sanish kumar #include <linux/iio/consumer.h> 2419939860Sanish kumar #include <linux/extcon/extcon-adc-jack.h> 2519939860Sanish kumar #include <linux/extcon.h> 2619939860Sanish kumar 2719939860Sanish kumar /** 2819939860Sanish kumar * struct adc_jack_data - internal data for adc_jack device driver 2919939860Sanish kumar * @edev - extcon device. 3019939860Sanish kumar * @cable_names - list of supported cables. 3119939860Sanish kumar * @num_cables - size of cable_names. 3219939860Sanish kumar * @adc_conditions - list of adc value conditions. 3319939860Sanish kumar * @num_conditions - size of adc_conditions. 3419939860Sanish kumar * @irq - irq number of attach/detach event (0 if not exist). 3519939860Sanish kumar * @handling_delay - interrupt handler will schedule extcon event 3619939860Sanish kumar * handling at handling_delay jiffies. 3719939860Sanish kumar * @handler - extcon event handler called by interrupt handler. 3819939860Sanish kumar * @chan - iio channel being queried. 3919939860Sanish kumar */ 4019939860Sanish kumar struct adc_jack_data { 4119939860Sanish kumar struct extcon_dev edev; 4219939860Sanish kumar 4319939860Sanish kumar const char **cable_names; 4419939860Sanish kumar int num_cables; 4519939860Sanish kumar struct adc_jack_cond *adc_conditions; 4619939860Sanish kumar int num_conditions; 4719939860Sanish kumar 4819939860Sanish kumar int irq; 4919939860Sanish kumar unsigned long handling_delay; /* in jiffies */ 5019939860Sanish kumar struct delayed_work handler; 5119939860Sanish kumar 5219939860Sanish kumar struct iio_channel *chan; 5319939860Sanish kumar }; 5419939860Sanish kumar 5519939860Sanish kumar static void adc_jack_handler(struct work_struct *work) 5619939860Sanish kumar { 5719939860Sanish kumar struct adc_jack_data *data = container_of(to_delayed_work(work), 5819939860Sanish kumar struct adc_jack_data, 5919939860Sanish kumar handler); 6019939860Sanish kumar u32 state = 0; 6119939860Sanish kumar int ret, adc_val; 6219939860Sanish kumar int i; 6319939860Sanish kumar 6419939860Sanish kumar ret = iio_read_channel_raw(data->chan, &adc_val); 6519939860Sanish kumar if (ret < 0) { 6619939860Sanish kumar dev_err(data->edev.dev, "read channel() error: %d\n", ret); 6719939860Sanish kumar return; 6819939860Sanish kumar } 6919939860Sanish kumar 7019939860Sanish kumar /* Get state from adc value with adc_conditions */ 7119939860Sanish kumar for (i = 0; i < data->num_conditions; i++) { 7219939860Sanish kumar struct adc_jack_cond *def = &data->adc_conditions[i]; 7319939860Sanish kumar if (!def->state) 7419939860Sanish kumar break; 7519939860Sanish kumar if (def->min_adc <= adc_val && def->max_adc >= adc_val) { 7619939860Sanish kumar state = def->state; 7719939860Sanish kumar break; 7819939860Sanish kumar } 7919939860Sanish kumar } 8019939860Sanish kumar /* if no def has met, it means state = 0 (no cables attached) */ 8119939860Sanish kumar 8219939860Sanish kumar extcon_set_state(&data->edev, state); 8319939860Sanish kumar } 8419939860Sanish kumar 8519939860Sanish kumar static irqreturn_t adc_jack_irq_thread(int irq, void *_data) 8619939860Sanish kumar { 8719939860Sanish kumar struct adc_jack_data *data = _data; 8819939860Sanish kumar 8919939860Sanish kumar schedule_delayed_work(&data->handler, data->handling_delay); 9019939860Sanish kumar return IRQ_HANDLED; 9119939860Sanish kumar } 9219939860Sanish kumar 9319939860Sanish kumar static int __devinit adc_jack_probe(struct platform_device *pdev) 9419939860Sanish kumar { 9519939860Sanish kumar struct adc_jack_data *data; 9619939860Sanish kumar struct adc_jack_pdata *pdata = pdev->dev.platform_data; 9719939860Sanish kumar int i, err = 0; 9819939860Sanish kumar 9919939860Sanish kumar data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); 10019939860Sanish kumar if (!data) 10119939860Sanish kumar return -ENOMEM; 10219939860Sanish kumar 10319939860Sanish kumar data->edev.name = pdata->name; 10419939860Sanish kumar 10519939860Sanish kumar if (!pdata->cable_names) { 10619939860Sanish kumar err = -EINVAL; 10719939860Sanish kumar dev_err(&pdev->dev, "error: cable_names not defined.\n"); 10819939860Sanish kumar goto out; 10919939860Sanish kumar } 11019939860Sanish kumar 11119939860Sanish kumar data->edev.supported_cable = pdata->cable_names; 11219939860Sanish kumar 11319939860Sanish kumar /* Check the length of array and set num_cables */ 11419939860Sanish kumar for (i = 0; data->edev.supported_cable[i]; i++) 11519939860Sanish kumar ; 11619939860Sanish kumar if (i == 0 || i > SUPPORTED_CABLE_MAX) { 11719939860Sanish kumar err = -EINVAL; 11819939860Sanish kumar dev_err(&pdev->dev, "error: pdata->cable_names size = %d\n", 11919939860Sanish kumar i - 1); 12019939860Sanish kumar goto out; 12119939860Sanish kumar } 12219939860Sanish kumar data->num_cables = i; 12319939860Sanish kumar 12419939860Sanish kumar if (!pdata->adc_conditions || 12519939860Sanish kumar !pdata->adc_conditions[0].state) { 12619939860Sanish kumar err = -EINVAL; 12719939860Sanish kumar dev_err(&pdev->dev, "error: adc_conditions not defined.\n"); 12819939860Sanish kumar goto out; 12919939860Sanish kumar } 13019939860Sanish kumar data->adc_conditions = pdata->adc_conditions; 13119939860Sanish kumar 13219939860Sanish kumar /* Check the length of array and set num_conditions */ 13319939860Sanish kumar for (i = 0; data->adc_conditions[i].state; i++) 13419939860Sanish kumar ; 13519939860Sanish kumar data->num_conditions = i; 13619939860Sanish kumar 13719939860Sanish kumar data->chan = iio_channel_get(dev_name(&pdev->dev), 13819939860Sanish kumar pdata->consumer_channel); 13919939860Sanish kumar if (IS_ERR(data->chan)) { 14019939860Sanish kumar err = PTR_ERR(data->chan); 14119939860Sanish kumar goto out; 14219939860Sanish kumar } 14319939860Sanish kumar 14419939860Sanish kumar data->handling_delay = msecs_to_jiffies(pdata->handling_delay_ms); 14519939860Sanish kumar 146*033d9959SLinus Torvalds INIT_DEFERRABLE_WORK(&data->handler, adc_jack_handler); 14719939860Sanish kumar 14819939860Sanish kumar platform_set_drvdata(pdev, data); 14919939860Sanish kumar 15019939860Sanish kumar err = extcon_dev_register(&data->edev, &pdev->dev); 15119939860Sanish kumar if (err) 15219939860Sanish kumar goto out; 15319939860Sanish kumar 15419939860Sanish kumar data->irq = platform_get_irq(pdev, 0); 15519939860Sanish kumar if (!data->irq) { 15619939860Sanish kumar dev_err(&pdev->dev, "platform_get_irq failed\n"); 15719939860Sanish kumar err = -ENODEV; 15819939860Sanish kumar goto err_irq; 15919939860Sanish kumar } 16019939860Sanish kumar 16119939860Sanish kumar err = request_any_context_irq(data->irq, adc_jack_irq_thread, 16219939860Sanish kumar pdata->irq_flags, pdata->name, data); 16319939860Sanish kumar 16419939860Sanish kumar if (err) { 16519939860Sanish kumar dev_err(&pdev->dev, "error: irq %d\n", data->irq); 16619939860Sanish kumar err = -EINVAL; 16719939860Sanish kumar goto err_irq; 16819939860Sanish kumar } 16919939860Sanish kumar 17019939860Sanish kumar goto out; 17119939860Sanish kumar 17219939860Sanish kumar err_irq: 17319939860Sanish kumar extcon_dev_unregister(&data->edev); 17419939860Sanish kumar out: 17519939860Sanish kumar return err; 17619939860Sanish kumar } 17719939860Sanish kumar 17819939860Sanish kumar static int __devexit adc_jack_remove(struct platform_device *pdev) 17919939860Sanish kumar { 18019939860Sanish kumar struct adc_jack_data *data = platform_get_drvdata(pdev); 18119939860Sanish kumar 18219939860Sanish kumar free_irq(data->irq, data); 18319939860Sanish kumar cancel_work_sync(&data->handler.work); 18419939860Sanish kumar extcon_dev_unregister(&data->edev); 18519939860Sanish kumar 18619939860Sanish kumar return 0; 18719939860Sanish kumar } 18819939860Sanish kumar 18919939860Sanish kumar static struct platform_driver adc_jack_driver = { 19019939860Sanish kumar .probe = adc_jack_probe, 19119939860Sanish kumar .remove = __devexit_p(adc_jack_remove), 19219939860Sanish kumar .driver = { 19319939860Sanish kumar .name = "adc-jack", 19419939860Sanish kumar .owner = THIS_MODULE, 19519939860Sanish kumar }, 19619939860Sanish kumar }; 19719939860Sanish kumar 19819939860Sanish kumar module_platform_driver(adc_jack_driver); 199