1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534 |
- /* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
- #include <linux/kernel.h>
- #include <linux/init.h>
- #include <linux/mutex.h>
- #include <linux/platform_device.h>
- #include <linux/err.h>
- #include <linux/hwmon.h>
- #include <linux/hwmon-sysfs.h>
- #include <linux/miscdevice.h>
- #include <linux/fs.h>
- #include <linux/sched.h>
- #include <linux/wait.h>
- #include <linux/uaccess.h>
- #include <linux/msm_adc.h>
- #include <linux/pmic8058-xoadc.h>
- #include <linux/slab.h>
- #include <linux/semaphore.h>
- #include <linux/module.h>
- #include <mach/dal.h>
- #define MSM_ADC_DRIVER_NAME "msm_adc"
- #define MSM_ADC_MAX_FNAME 15
- #define MSM_ADC_DALRPC_DEVICEID 0x02000067
- #define MSM_ADC_DALRPC_PORT_NAME "DAL00"
- #define MSM_ADC_DALRPC_CPU SMD_APPS_MODEM
- #define MSM_ADC_DALRPC_CMD_REQ_CONV 9
- #define MSM_ADC_DALRPC_CMD_INPUT_PROP 11
- #define MSM_ADC_DALRC_CONV_TIMEOUT (5 * HZ) /* 5 seconds */
- #define MSM_8x25_ADC_DEV_ID 0
- #define MSM_8x25_CHAN_ID 16
- enum dal_error {
- DAL_ERROR_INVALID_DEVICE_IDX = 1,
- DAL_ERROR_INVALID_CHANNEL_IDX,
- DAL_ERROR_NULL_POINTER,
- DAL_ERROR_DEVICE_QUEUE_FULL,
- DAL_ERROR_INVALID_PROPERTY_LENGTH,
- DAL_ERROR_REMOTE_EVENT_POOL_FULL
- };
- enum dal_result_status {
- DAL_RESULT_STATUS_INVALID,
- DAL_RESULT_STATUS_VALID
- };
- struct dal_conv_state {
- struct dal_conv_slot context[MSM_ADC_DEV_MAX_INFLIGHT];
- struct list_head slots;
- struct mutex list_lock;
- struct semaphore slot_count;
- };
- struct adc_dev {
- char *name;
- uint32_t nchans;
- struct dal_conv_state conv;
- struct dal_translation transl;
- struct sensor_device_attribute *sens_attr;
- char **fnames;
- };
- struct msm_adc_drv {
- /* Common to both XOADC and EPM */
- struct platform_device *pdev;
- struct device *hwmon;
- struct miscdevice misc;
- /* XOADC variables */
- struct sensor_device_attribute *sens_attr;
- struct workqueue_struct *wq;
- atomic_t online;
- atomic_t total_outst;
- wait_queue_head_t total_outst_wait;
- /* EPM variables */
- void *dev_h;
- struct adc_dev *devs[MSM_ADC_MAX_NUM_DEVS];
- struct mutex prop_lock;
- atomic_t rpc_online;
- atomic_t rpc_total_outst;
- wait_queue_head_t rpc_total_outst_wait;
- };
- static bool epm_init;
- static bool epm_fluid_enabled;
- /* Needed to support file_op interfaces */
- static struct msm_adc_drv *msm_adc_drv;
- static bool conv_first_request;
- static ssize_t msm_adc_show_curr(struct device *dev,
- struct device_attribute *devattr, char *buf);
- static int msm_rpc_adc_blocking_conversion(struct msm_adc_drv *msm_adc,
- uint32_t chan, struct adc_chan_result *result);
- static int msm_adc_blocking_conversion(struct msm_adc_drv *msm_adc,
- uint32_t chan, struct adc_chan_result *result);
- static int msm_adc_open(struct inode *inode, struct file *file)
- {
- struct msm_client_data *client;
- struct msm_adc_drv *msm_adc = msm_adc_drv;
- struct platform_device *pdev = msm_adc->pdev;
- client = kzalloc(sizeof(struct msm_client_data), GFP_KERNEL);
- if (!client) {
- dev_err(&pdev->dev, "Unable to allocate memory\n");
- return -ENOMEM;
- }
- if (!try_module_get(THIS_MODULE)) {
- kfree(client);
- return -EACCES;
- }
- mutex_init(&client->lock);
- INIT_LIST_HEAD(&client->complete_list);
- init_waitqueue_head(&client->data_wait);
- init_waitqueue_head(&client->outst_wait);
- client->online = 1;
- file->private_data = client;
- return nonseekable_open(inode, file);
- }
- static inline void msm_adc_restore_slot(struct dal_conv_state *conv_s,
- struct dal_conv_slot *slot)
- {
- mutex_lock(&conv_s->list_lock);
- list_add(&slot->list, &conv_s->slots);
- mutex_unlock(&conv_s->list_lock);
- up(&conv_s->slot_count);
- }
- static int no_pending_client_requests(struct msm_client_data *client)
- {
- mutex_lock(&client->lock);
- if (client->num_outstanding == 0) {
- mutex_unlock(&client->lock);
- return 1;
- }
- mutex_unlock(&client->lock);
- return 0;
- }
- static int data_avail(struct msm_client_data *client, uint32_t *pending)
- {
- uint32_t completed;
- mutex_lock(&client->lock);
- completed = client->num_complete;
- mutex_unlock(&client->lock);
- if (completed > 0) {
- if (pending != NULL)
- *pending = completed;
- return 1;
- }
- return 0;
- }
- static int msm_adc_release(struct inode *inode, struct file *file)
- {
- struct msm_client_data *client = file->private_data;
- struct adc_conv_slot *slot, *tmp;
- int rc;
- struct msm_adc_platform_data *pdata =
- msm_adc_drv->pdev->dev.platform_data;
- struct msm_adc_channels *channel = pdata->channel;
- module_put(THIS_MODULE);
- mutex_lock(&client->lock);
- /* prevent any further requests while we teardown the client */
- client->online = 0;
- mutex_unlock(&client->lock);
- /*
- * We may still have outstanding transactions in flight from this
- * client that have not completed. Make sure they're completed
- * before removing the client.
- */
- rc = wait_event_interruptible(client->outst_wait,
- no_pending_client_requests(client));
- if (rc) {
- pr_err("%s: wait_event_interruptible failed rc = %d\n",
- __func__, rc);
- return rc;
- }
- /*
- * All transactions have completed. Add slot resources back to the
- * appropriate devices.
- */
- list_for_each_entry_safe(slot, tmp, &client->complete_list, list) {
- slot->client = NULL;
- list_del(&slot->list);
- channel[slot->conv.result.chan].adc_access_fn->adc_restore_slot(
- channel[slot->conv.result.chan].adc_dev_instance, slot);
- }
- kfree(client);
- return 0;
- }
- static int msm_adc_translate_dal_to_hwmon(struct msm_adc_drv *msm_adc,
- uint32_t chan,
- struct adc_dev_spec *dest)
- {
- struct dal_translation *transl;
- struct msm_adc_platform_data *pdata = msm_adc->pdev->dev.platform_data;
- int i;
- for (i = 0; i < pdata->num_adc; i++) {
- transl = &msm_adc->devs[i]->transl;
- if (chan >= transl->hwmon_start &&
- chan <= transl->hwmon_end) {
- dest->dal.dev_idx = transl->dal_dev_idx;
- dest->hwmon_dev_idx = transl->hwmon_dev_idx;
- dest->dal.chan_idx = chan - transl->hwmon_start;
- return 0;
- }
- }
- return -EINVAL;
- }
- static int msm_adc_translate_hwmon_to_dal(struct msm_adc_drv *msm_adc,
- struct adc_dev_spec *source,
- uint32_t *chan)
- {
- struct msm_adc_platform_data *pdata = msm_adc->pdev->dev.platform_data;
- struct dal_translation *transl;
- int i;
- for (i = 0; i < pdata->num_adc; i++) {
- transl = &msm_adc->devs[i]->transl;
- if (source->dal.dev_idx != transl->dal_dev_idx)
- continue;
- *chan = transl->hwmon_start + source->dal.chan_idx;
- return 0;
- }
- return -EINVAL;
- }
- static int msm_adc_getinputproperties(struct msm_adc_drv *msm_adc,
- const char *lookup_name,
- struct adc_dev_spec *result)
- {
- struct device *dev = &msm_adc->pdev->dev;
- int rc;
- mutex_lock(&msm_adc->prop_lock);
- rc = dalrpc_fcn_8(MSM_ADC_DALRPC_CMD_INPUT_PROP, msm_adc->dev_h,
- lookup_name, strlen(lookup_name) + 1,
- &result->dal, sizeof(struct dal_dev_spec));
- if (rc) {
- dev_err(dev, "DAL getprop request failed: rc = %d\n", rc);
- mutex_unlock(&msm_adc->prop_lock);
- return -EIO;
- }
- mutex_unlock(&msm_adc->prop_lock);
- return rc;
- }
- static int msm_adc_lookup(struct msm_adc_drv *msm_adc,
- struct msm_adc_lookup *lookup)
- {
- struct msm_adc_platform_data *pdata = msm_adc->pdev->dev.platform_data;
- struct adc_dev_spec target;
- int rc = 0, i = 0;
- uint32_t len = 0;
- len = strnlen(lookup->name, MSM_ADC_MAX_CHAN_STR);
- while (i < pdata->num_chan_supported) {
- if (strncmp(lookup->name, pdata->channel[i].name, len))
- i++;
- else
- break;
- }
- if (pdata->num_chan_supported > 0 && i < pdata->num_chan_supported) {
- lookup->chan_idx = i;
- } else if (msm_adc->dev_h) {
- rc = msm_adc_getinputproperties(msm_adc, lookup->name, &target);
- if (rc) {
- pr_err("%s: Lookup failed for %s\n", __func__,
- lookup->name);
- return rc;
- }
- rc = msm_adc_translate_hwmon_to_dal(msm_adc, &target,
- &lookup->chan_idx);
- if (rc)
- pr_err("%s: Translation failed for %s\n", __func__,
- lookup->name);
- } else {
- pr_err("%s: Lookup failed for %s\n", __func__, lookup->name);
- rc = -EINVAL;
- }
- return rc;
- }
- static int msm_adc_aio_conversion(struct msm_adc_drv *msm_adc,
- struct adc_chan_result *request,
- struct msm_client_data *client)
- {
- struct msm_adc_platform_data *pdata =
- msm_adc_drv->pdev->dev.platform_data;
- struct msm_adc_channels *channel = &pdata->channel[request->chan];
- struct adc_conv_slot *slot;
- /* we could block here, but only for a bounded time */
- channel->adc_access_fn->adc_slot_request(channel->adc_dev_instance,
- &slot);
- if (slot) {
- atomic_inc(&msm_adc->total_outst);
- mutex_lock(&client->lock);
- client->num_outstanding++;
- mutex_unlock(&client->lock);
- /* indicates non blocking request to callback handler */
- slot->blocking = 0;
- slot->compk = NULL;/*For kernel space usage; n/a for usr space*/
- slot->conv.result.chan = client->adc_chan = request->chan;
- slot->client = client;
- slot->adc_request = START_OF_CONV;
- slot->chan_path = channel->chan_path_type;
- slot->chan_adc_config = channel->adc_config_type;
- slot->chan_adc_calib = channel->adc_calib_type;
- queue_work(msm_adc->wq, &slot->work);
- return 0;
- }
- return -EBUSY;
- }
- static int msm_adc_fluid_hw_deinit(struct msm_adc_drv *msm_adc)
- {
- struct msm_adc_platform_data *pdata = msm_adc->pdev->dev.platform_data;
- if (!epm_init)
- return -EINVAL;
- if (pdata->gpio_config == APROC_CONFIG &&
- epm_fluid_enabled && pdata->adc_fluid_disable != NULL) {
- pdata->adc_fluid_disable();
- epm_fluid_enabled = false;
- }
- return 0;
- }
- static int msm_adc_fluid_hw_init(struct msm_adc_drv *msm_adc)
- {
- struct msm_adc_platform_data *pdata = msm_adc->pdev->dev.platform_data;
- if (!epm_init)
- return -EINVAL;
- if (!pdata->adc_fluid_enable)
- return -ENODEV;
- printk(KERN_DEBUG "msm_adc_fluid_hw_init: Calling adc_fluid_enable.\n");
- if (pdata->gpio_config == APROC_CONFIG && !epm_fluid_enabled) {
- pdata->adc_fluid_enable();
- epm_fluid_enabled = true;
- }
- /* return success for now but check for errors from hw init configuration */
- return 0;
- }
- static int msm_adc_poll_complete(struct msm_adc_drv *msm_adc,
- struct msm_client_data *client, uint32_t *pending)
- {
- int rc;
- /*
- * Don't proceed if there there's nothing queued on this client.
- * We could deadlock otherwise in a single threaded scenario.
- */
- if (no_pending_client_requests(client) && !data_avail(client, pending))
- return -EDEADLK;
- rc = wait_event_interruptible(client->data_wait,
- data_avail(client, pending));
- if (rc)
- return rc;
- return 0;
- }
- static int msm_adc_read_result(struct msm_adc_drv *msm_adc,
- struct msm_client_data *client,
- struct adc_chan_result *result)
- {
- struct msm_adc_platform_data *pdata = msm_adc->pdev->dev.platform_data;
- struct msm_adc_channels *channel = pdata->channel;
- struct adc_conv_slot *slot;
- int rc = 0;
- mutex_lock(&client->lock);
- slot = list_first_entry(&client->complete_list,
- struct adc_conv_slot, list);
- if (!slot) {
- mutex_unlock(&client->lock);
- return -ENOMSG;
- }
- slot->client = NULL;
- list_del(&slot->list);
- client->num_complete--;
- mutex_unlock(&client->lock);
- *result = slot->conv.result;
- /* restore this slot to reserve */
- channel[slot->conv.result.chan].adc_access_fn->adc_restore_slot(
- channel[slot->conv.result.chan].adc_dev_instance, slot);
- return rc;
- }
- static long msm_adc_ioctl(struct file *file, unsigned int cmd,
- unsigned long arg)
- {
- struct msm_client_data *client = file->private_data;
- struct msm_adc_drv *msm_adc = msm_adc_drv;
- struct platform_device *pdev = msm_adc->pdev;
- struct msm_adc_platform_data *pdata = pdev->dev.platform_data;
- uint32_t block_res = 0;
- int rc;
- switch (cmd) {
- case MSM_ADC_REQUEST:
- {
- struct adc_chan_result conv;
- if (copy_from_user(&conv, (void __user *)arg,
- sizeof(struct adc_chan_result)))
- return -EFAULT;
- if (conv.chan < pdata->num_chan_supported) {
- rc = msm_adc_blocking_conversion(msm_adc,
- conv.chan, &conv);
- } else {
- if (!msm_adc->dev_h)
- return -EAGAIN;
- rc = msm_rpc_adc_blocking_conversion(msm_adc,
- conv.chan, &conv);
- }
- if (rc) {
- dev_dbg(&pdev->dev, "BLK conversion failed\n");
- return rc;
- }
- if (copy_to_user((void __user *)arg, &conv,
- sizeof(struct adc_chan_result)))
- return -EFAULT;
- break;
- }
- case MSM_ADC_AIO_REQUEST_BLOCK_RES:
- block_res = 1;
- case MSM_ADC_AIO_REQUEST:
- {
- struct adc_chan_result conv;
- if (copy_from_user(&conv, (void __user *)arg,
- sizeof(struct adc_chan_result)))
- return -EFAULT;
- if (conv.chan >= pdata->num_chan_supported)
- return -EINVAL;
- rc = msm_adc_aio_conversion(msm_adc, &conv, client);
- if (rc) {
- dev_dbg(&pdev->dev, "AIO conversion failed\n");
- return rc;
- }
- if (copy_to_user((void __user *)arg, &conv,
- sizeof(struct adc_chan_result)))
- return -EFAULT;
- break;
- }
- case MSM_ADC_AIO_POLL:
- {
- uint32_t completed;
- rc = msm_adc_poll_complete(msm_adc, client, &completed);
- if (rc) {
- dev_dbg(&pdev->dev, "poll request failed\n");
- return rc;
- }
- if (copy_to_user((void __user *)arg, &completed,
- sizeof(uint32_t)))
- return -EFAULT;
- break;
- }
- case MSM_ADC_AIO_READ:
- {
- struct adc_chan_result result;
- rc = msm_adc_read_result(msm_adc, client, &result);
- if (rc) {
- dev_dbg(&pdev->dev, "read result failed\n");
- return rc;
- }
- if (copy_to_user((void __user *)arg, &result,
- sizeof(struct adc_chan_result)))
- return -EFAULT;
- break;
- }
- case MSM_ADC_LOOKUP:
- {
- struct msm_adc_lookup lookup;
- if (copy_from_user(&lookup, (void __user *)arg,
- sizeof(struct msm_adc_lookup)))
- return -EFAULT;
- rc = msm_adc_lookup(msm_adc, &lookup);
- if (rc) {
- dev_dbg(&pdev->dev, "No such channel: %s\n",
- lookup.name);
- return rc;
- }
- if (copy_to_user((void __user *)arg, &lookup,
- sizeof(struct msm_adc_lookup)))
- return -EFAULT;
- break;
- }
- case MSM_ADC_FLUID_INIT:
- {
- uint32_t result;
- result = msm_adc_fluid_hw_init(msm_adc);
- if (copy_to_user((void __user *)arg, &result,
- sizeof(uint32_t))) {
- printk(KERN_ERR "MSM_ADC_FLUID_INIT: "
- "copy_to_user returned an error.\n");
- return -EFAULT;
- }
- printk(KERN_DEBUG "MSM_ADC_FLUID_INIT: Success.\n");
- break;
- }
- case MSM_ADC_FLUID_DEINIT:
- {
- uint32_t result;
- result = msm_adc_fluid_hw_deinit(msm_adc);
- if (copy_to_user((void __user *)arg, &result,
- sizeof(uint32_t)))
- return -EFAULT;
- break;
- }
- default:
- return -EINVAL;
- }
- return 0;
- }
- const struct file_operations msm_adc_fops = {
- .open = msm_adc_open,
- .release = msm_adc_release,
- .unlocked_ioctl = msm_adc_ioctl,
- };
- static ssize_t msm_adc_show_curr(struct device *dev,
- struct device_attribute *devattr, char *buf)
- {
- struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct msm_adc_drv *msm_adc = dev_get_drvdata(dev);
- struct msm_adc_platform_data *pdata = msm_adc->pdev->dev.platform_data;
- struct adc_chan_result result;
- int rc;
- #ifdef CONFIG_PMIC8058_XOADC
- rc = pm8058_xoadc_registered();
- if (rc <= 0)
- return -ENODEV;
- #endif
- if (attr->index < pdata->num_chan_supported) {
- rc = msm_adc_blocking_conversion(msm_adc,
- attr->index, &result);
- } else {
- if (pdata->gpio_config == APROC_CONFIG && !epm_fluid_enabled
- && pdata->adc_fluid_enable != NULL) {
- printk(KERN_DEBUG "This is to read ADC value for "
- "Fluid EPM and init. Do it only once.\n");
- pdata->adc_fluid_enable();
- epm_fluid_enabled = true;
- }
- rc = msm_rpc_adc_blocking_conversion(msm_adc,
- attr->index, &result);
- }
- if (rc)
- return 0;
- return sprintf(buf, "Result: %lld Raw: %d\n", result.physical,
- result.adc_code);
- }
- static int msm_rpc_adc_blocking_conversion(struct msm_adc_drv *msm_adc,
- uint32_t hwmon_chan, struct adc_chan_result *result)
- {
- struct msm_adc_platform_data *pdata = msm_adc->pdev->dev.platform_data;
- struct dal_conv_request params;
- struct device *dev = &msm_adc->pdev->dev;
- struct adc_dev *adc_dev;
- struct dal_conv_state *conv_s;
- struct dal_conv_slot *slot;
- struct adc_dev_spec dest;
- int timeout, rc = 0;
- if (pdata->gpio_config == APROC_CONFIG &&
- pdata->adc_gpio_enable != NULL)
- pdata->adc_gpio_enable(hwmon_chan-pdata->num_chan_supported);
- rc = msm_adc_translate_dal_to_hwmon(msm_adc, hwmon_chan, &dest);
- if (rc) {
- dev_err(dev, "%s: translation from chan %u failed\n",
- __func__, hwmon_chan);
- if (pdata->gpio_config == APROC_CONFIG &&
- pdata->adc_gpio_disable != NULL)
- pdata->adc_gpio_disable(hwmon_chan
- -pdata->num_chan_supported);
- return -EINVAL;
- }
- adc_dev = msm_adc->devs[dest.hwmon_dev_idx];
- conv_s = &adc_dev->conv;
- down(&conv_s->slot_count);
- mutex_lock(&conv_s->list_lock);
- slot = list_first_entry(&conv_s->slots, struct dal_conv_slot, list);
- list_del(&slot->list);
- BUG_ON(!slot);
- mutex_unlock(&conv_s->list_lock);
- /* indicates blocking request to callback handler */
- slot->blocking = 1;
- params.target.dev_idx = dest.dal.dev_idx;
- params.target.chan_idx = dest.dal.chan_idx;
- params.cb_h = slot->cb_h;
- rc = dalrpc_fcn_8(MSM_ADC_DALRPC_CMD_REQ_CONV, msm_adc->dev_h,
- ¶ms, sizeof(params), NULL, 0);
- if (rc) {
- dev_err(dev, "%s: Conversion for device = %u channel = %u"
- " failed\n", __func__, params.target.dev_idx,
- params.target.chan_idx);
- rc = -EIO;
- goto blk_conv_err;
- }
- timeout = wait_for_completion_interruptible_timeout(&slot->comp,
- MSM_ADC_DALRC_CONV_TIMEOUT);
- if (timeout == 0) {
- dev_err(dev, "read for device = %u channel = %u timed out\n",
- params.target.dev_idx, params.target.chan_idx);
- rc = -ETIMEDOUT;
- goto blk_conv_err;
- } else if (timeout < 0) {
- rc = -EINTR;
- goto blk_conv_err;
- }
- result->physical = (int64_t)slot->result.physical;
- if (slot->result.status == DAL_RESULT_STATUS_INVALID)
- rc = -ENODATA;
- blk_conv_err:
- if (pdata->gpio_config == APROC_CONFIG &&
- pdata->adc_gpio_disable != NULL)
- pdata->adc_gpio_disable(hwmon_chan-pdata->num_chan_supported);
- msm_adc_restore_slot(conv_s, slot);
- return rc;
- }
- static int msm_adc_blocking_conversion(struct msm_adc_drv *msm_adc,
- uint32_t hwmon_chan, struct adc_chan_result *result)
- {
- struct adc_conv_slot *slot;
- struct msm_adc_platform_data *pdata =
- msm_adc_drv->pdev->dev.platform_data;
- struct msm_adc_channels *channel = &pdata->channel[hwmon_chan];
- int ret = 0;
- if (conv_first_request) {
- ret = pm8058_xoadc_calib_device(channel->adc_dev_instance);
- if (ret) {
- pr_err("pmic8058 xoadc calibration failed, retry\n");
- return ret;
- }
- conv_first_request = false;
- }
- channel->adc_access_fn->adc_slot_request(channel->adc_dev_instance,
- &slot);
- if (slot) {
- slot->conv.result.chan = hwmon_chan;
- /* indicates blocking request to callback handler */
- slot->blocking = 1;
- slot->adc_request = START_OF_CONV;
- slot->chan_path = channel->chan_path_type;
- slot->chan_adc_config = channel->adc_config_type;
- slot->chan_adc_calib = channel->adc_calib_type;
- queue_work(msm_adc_drv->wq, &slot->work);
- wait_for_completion_interruptible(&slot->comp);
- *result = slot->conv.result;
- channel->adc_access_fn->adc_restore_slot(
- channel->adc_dev_instance, slot);
- return 0;
- }
- return -EBUSY;
- }
- int32_t adc_channel_open(uint32_t channel, void **h)
- {
- struct msm_client_data *client;
- struct msm_adc_drv *msm_adc = msm_adc_drv;
- struct msm_adc_platform_data *pdata;
- struct platform_device *pdev;
- int i = 0;
- if (!msm_adc_drv)
- return -EFAULT;
- #ifdef CONFIG_PMIC8058_XOADC
- if (pm8058_xoadc_registered() <= 0)
- return -ENODEV;
- #endif
- pdata = msm_adc->pdev->dev.platform_data;
- pdev = msm_adc->pdev;
- while (i < pdata->num_chan_supported) {
- if (channel == pdata->channel[i].channel_name)
- break;
- else
- i++;
- }
- if (i == pdata->num_chan_supported)
- return -EBADF; /* unknown channel */
- client = kzalloc(sizeof(struct msm_client_data), GFP_KERNEL);
- if (!client) {
- dev_err(&pdev->dev, "Unable to allocate memory\n");
- return -ENOMEM;
- }
- if (!try_module_get(THIS_MODULE)) {
- kfree(client);
- return -EACCES;
- }
- mutex_init(&client->lock);
- INIT_LIST_HEAD(&client->complete_list);
- init_waitqueue_head(&client->data_wait);
- init_waitqueue_head(&client->outst_wait);
- client->online = 1;
- client->adc_chan = i;
- *h = (void *)client;
- return 0;
- }
- int32_t adc_channel_close(void *h)
- {
- struct msm_client_data *client = (struct msm_client_data *)h;
- kfree(client);
- return 0;
- }
- int32_t adc_channel_request_conv(void *h, struct completion *conv_complete_evt)
- {
- struct msm_client_data *client = (struct msm_client_data *)h;
- struct msm_adc_platform_data *pdata =
- msm_adc_drv->pdev->dev.platform_data;
- struct msm_adc_channels *channel = &pdata->channel[client->adc_chan];
- struct adc_conv_slot *slot;
- int ret;
- if (conv_first_request) {
- ret = pm8058_xoadc_calib_device(channel->adc_dev_instance);
- if (ret) {
- pr_err("pmic8058 xoadc calibration failed, retry\n");
- return ret;
- }
- conv_first_request = false;
- }
- channel->adc_access_fn->adc_slot_request(channel->adc_dev_instance,
- &slot);
- if (slot) {
- atomic_inc(&msm_adc_drv->total_outst);
- mutex_lock(&client->lock);
- client->num_outstanding++;
- mutex_unlock(&client->lock);
- slot->conv.result.chan = client->adc_chan;
- slot->blocking = 0;
- slot->compk = conv_complete_evt;
- slot->client = client;
- slot->adc_request = START_OF_CONV;
- slot->chan_path = channel->chan_path_type;
- slot->chan_adc_config = channel->adc_config_type;
- slot->chan_adc_calib = channel->adc_calib_type;
- queue_work(msm_adc_drv->wq, &slot->work);
- return 0;
- }
- return -EBUSY;
- }
- int32_t adc_channel_read_result(void *h, struct adc_chan_result *chan_result)
- {
- struct msm_client_data *client = (struct msm_client_data *)h;
- struct msm_adc_platform_data *pdata =
- msm_adc_drv->pdev->dev.platform_data;
- struct msm_adc_channels *channel = pdata->channel;
- struct adc_conv_slot *slot;
- int rc = 0;
- mutex_lock(&client->lock);
- slot = list_first_entry(&client->complete_list,
- struct adc_conv_slot, list);
- if (!slot) {
- mutex_unlock(&client->lock);
- return -ENOMSG;
- }
- slot->client = NULL;
- list_del(&slot->list);
- client->num_complete--;
- mutex_unlock(&client->lock);
- *chan_result = slot->conv.result;
- /* restore this slot to reserve */
- channel[slot->conv.result.chan].adc_access_fn->adc_restore_slot(
- channel[slot->conv.result.chan].adc_dev_instance, slot);
- return rc;
- }
- static void msm_rpc_adc_conv_cb(void *context, u32 param,
- void *evt_buf, u32 len)
- {
- struct dal_adc_result *result = evt_buf;
- struct dal_conv_slot *slot = context;
- struct msm_adc_drv *msm_adc = msm_adc_drv;
- memcpy(&slot->result, result, sizeof(slot->result));
- /* for blocking requests, signal complete */
- if (slot->blocking)
- complete(&slot->comp);
- /* for non-blocking requests, add slot to the client completed list */
- else {
- struct msm_client_data *client = slot->client;
- mutex_lock(&client->lock);
- list_add(&slot->list, &client->complete_list);
- client->num_complete++;
- client->num_outstanding--;
- /*
- * if the client release has been invoked and this is call
- * corresponds to the last request, then signal release
- * to complete.
- */
- if (slot->client->online == 0 && client->num_outstanding == 0)
- wake_up_interruptible_all(&client->outst_wait);
- mutex_unlock(&client->lock);
- wake_up_interruptible_all(&client->data_wait);
- atomic_dec(&msm_adc->total_outst);
- /* verify driver remove has not been invoked */
- if (atomic_read(&msm_adc->online) == 0 &&
- atomic_read(&msm_adc->total_outst) == 0)
- wake_up_interruptible_all(&msm_adc->total_outst_wait);
- }
- }
- void msm_adc_conv_cb(void *context, u32 param,
- void *evt_buf, u32 len)
- {
- struct adc_conv_slot *slot = context;
- struct msm_adc_drv *msm_adc = msm_adc_drv;
- switch (slot->adc_request) {
- case START_OF_CONV:
- slot->adc_request = END_OF_CONV;
- break;
- case START_OF_CALIBRATION:
- slot->adc_request = END_OF_CALIBRATION;
- break;
- case END_OF_CALIBRATION:
- case END_OF_CONV:
- break;
- }
- queue_work(msm_adc->wq, &slot->work);
- }
- static void msm_adc_teardown_device_conv(struct platform_device *pdev,
- struct adc_dev *adc_dev)
- {
- struct dal_conv_state *conv_s = &adc_dev->conv;
- struct msm_adc_drv *msm_adc = platform_get_drvdata(pdev);
- struct dal_conv_slot *slot;
- int i;
- for (i = 0; i < MSM_ADC_DEV_MAX_INFLIGHT; i++) {
- slot = &conv_s->context[i];
- if (slot->cb_h) {
- dalrpc_dealloc_cb(msm_adc->dev_h, slot->cb_h);
- slot->cb_h = NULL;
- }
- }
- }
- static void msm_rpc_adc_teardown_device(struct platform_device *pdev,
- struct adc_dev *adc_dev)
- {
- struct dal_translation *transl = &adc_dev->transl;
- int i, num_chans = transl->hwmon_end - transl->hwmon_start + 1;
- if (adc_dev->sens_attr)
- for (i = 0; i < num_chans; i++)
- device_remove_file(&pdev->dev,
- &adc_dev->sens_attr[i].dev_attr);
- msm_adc_teardown_device_conv(pdev, adc_dev);
- kfree(adc_dev->fnames);
- kfree(adc_dev->sens_attr);
- kfree(adc_dev);
- }
- static void msm_rpc_adc_teardown_devices(struct platform_device *pdev)
- {
- struct msm_adc_platform_data *pdata = pdev->dev.platform_data;
- struct msm_adc_drv *msm_adc = platform_get_drvdata(pdev);
- int i, rc = 0;
- for (i = 0; i < pdata->num_adc; i++) {
- if (msm_adc->devs[i]) {
- msm_rpc_adc_teardown_device(pdev, msm_adc->devs[i]);
- msm_adc->devs[i] = NULL;
- } else
- break;
- }
- if (msm_adc->dev_h) {
- rc = daldevice_detach(msm_adc->dev_h);
- if (rc)
- dev_err(&pdev->dev, "Cannot detach from dal device\n");
- msm_adc->dev_h = NULL;
- }
- }
- static void msm_adc_teardown_device(struct platform_device *pdev,
- struct msm_adc_drv *msm_adc)
- {
- struct msm_adc_platform_data *pdata = pdev->dev.platform_data;
- int i, num_chans = pdata->num_chan_supported;
- if (pdata->num_chan_supported > 0) {
- if (msm_adc->sens_attr)
- for (i = 0; i < num_chans; i++)
- device_remove_file(&pdev->dev,
- &msm_adc->sens_attr[i].dev_attr);
- kfree(msm_adc->sens_attr);
- }
- }
- static void msm_adc_teardown(struct platform_device *pdev)
- {
- struct msm_adc_drv *msm_adc = platform_get_drvdata(pdev);
- if (!msm_adc)
- return;
- misc_deregister(&msm_adc->misc);
- if (msm_adc->hwmon)
- hwmon_device_unregister(msm_adc->hwmon);
- msm_rpc_adc_teardown_devices(pdev);
- msm_adc_teardown_device(pdev, msm_adc);
- kfree(msm_adc);
- platform_set_drvdata(pdev, NULL);
- }
- static int __devinit msm_adc_device_conv_init(struct msm_adc_drv *msm_adc,
- struct adc_dev *adc_dev)
- {
- struct platform_device *pdev = msm_adc->pdev;
- struct dal_conv_state *conv_s = &adc_dev->conv;
- struct dal_conv_slot *slot = conv_s->context;
- int rc, i;
- sema_init(&conv_s->slot_count, MSM_ADC_DEV_MAX_INFLIGHT);
- mutex_init(&conv_s->list_lock);
- INIT_LIST_HEAD(&conv_s->slots);
- for (i = 0; i < MSM_ADC_DEV_MAX_INFLIGHT; i++) {
- list_add(&slot->list, &conv_s->slots);
- slot->cb_h = dalrpc_alloc_cb(msm_adc->dev_h,
- msm_rpc_adc_conv_cb, slot);
- if (!slot->cb_h) {
- dev_err(&pdev->dev, "Unable to allocate DAL callback"
- " for slot %d\n", i);
- rc = -ENOMEM;
- goto dal_err_cb;
- }
- init_completion(&slot->comp);
- slot->idx = i;
- slot++;
- }
- return 0;
- dal_err_cb:
- msm_adc_teardown_device_conv(pdev, adc_dev);
- return rc;
- }
- static struct sensor_device_attribute msm_rpc_adc_curr_in_attr =
- SENSOR_ATTR(NULL, S_IRUGO, msm_adc_show_curr, NULL, 0);
- static int __devinit msm_rpc_adc_device_init_hwmon(struct platform_device *pdev,
- struct adc_dev *adc_dev)
- {
- struct dal_translation *transl = &adc_dev->transl;
- int i, rc, num_chans = transl->hwmon_end - transl->hwmon_start + 1;
- const char prefix[] = "curr", postfix[] = "_input";
- char tmpbuf[5];
- adc_dev->fnames = kzalloc(num_chans * MSM_ADC_MAX_FNAME +
- num_chans * sizeof(char *), GFP_KERNEL);
- if (!adc_dev->fnames) {
- dev_err(&pdev->dev, "Unable to allocate memory\n");
- return -ENOMEM;
- }
- adc_dev->sens_attr = kzalloc(num_chans *
- sizeof(struct sensor_device_attribute), GFP_KERNEL);
- if (!adc_dev->sens_attr) {
- dev_err(&pdev->dev, "Unable to allocate memory\n");
- rc = -ENOMEM;
- goto hwmon_err_fnames;
- }
- for (i = 0; i < num_chans; i++) {
- adc_dev->fnames[i] = (char *)adc_dev->fnames +
- i * MSM_ADC_MAX_FNAME + num_chans * sizeof(char *);
- strcpy(adc_dev->fnames[i], prefix);
- sprintf(tmpbuf, "%d", transl->hwmon_start + i);
- strcat(adc_dev->fnames[i], tmpbuf);
- strcat(adc_dev->fnames[i], postfix);
- msm_rpc_adc_curr_in_attr.index = transl->hwmon_start + i;
- msm_rpc_adc_curr_in_attr.dev_attr.attr.name =
- adc_dev->fnames[i];
- memcpy(&adc_dev->sens_attr[i], &msm_rpc_adc_curr_in_attr,
- sizeof(msm_rpc_adc_curr_in_attr));
- rc = device_create_file(&pdev->dev,
- &adc_dev->sens_attr[i].dev_attr);
- if (rc) {
- dev_err(&pdev->dev, "device_create_file failed for "
- "dal dev %u chan %d\n",
- adc_dev->transl.dal_dev_idx, i);
- goto hwmon_err_sens;
- }
- }
- return 0;
- hwmon_err_sens:
- kfree(adc_dev->sens_attr);
- hwmon_err_fnames:
- kfree(adc_dev->fnames);
- return rc;
- }
- static int __devinit msm_rpc_adc_device_init(struct platform_device *pdev)
- {
- struct msm_adc_platform_data *pdata = pdev->dev.platform_data;
- struct msm_adc_drv *msm_adc = platform_get_drvdata(pdev);
- struct adc_dev *adc_dev;
- struct adc_dev_spec target;
- int i, rc;
- int hwmon_cntr = pdata->num_chan_supported;
- for (i = 0; i < pdata->num_adc; i++) {
- adc_dev = kzalloc(sizeof(struct adc_dev), GFP_KERNEL);
- if (!adc_dev) {
- dev_err(&pdev->dev, "Unable to allocate memory\n");
- rc = -ENOMEM;
- goto dev_init_err;
- }
- msm_adc->devs[i] = adc_dev;
- adc_dev->name = pdata->dev_names[i];
- rc = msm_adc_device_conv_init(msm_adc, adc_dev);
- if (rc) {
- dev_err(&pdev->dev, "DAL device[%s] failed conv init\n",
- adc_dev->name);
- goto dev_init_err;
- }
- if (!pdata->target_hw == MSM_8x25) {
- /* DAL device lookup */
- rc = msm_adc_getinputproperties(msm_adc, adc_dev->name,
- &target);
- if (rc) {
- dev_err(&pdev->dev, "No such DAL device[%s]\n",
- adc_dev->name);
- goto dev_init_err;
- }
- adc_dev->transl.dal_dev_idx = target.dal.dev_idx;
- adc_dev->nchans = target.dal.chan_idx;
- } else {
- /* On targets prior to MSM7x30 the remote driver has
- only the channel list and no device id. */
- adc_dev->transl.dal_dev_idx = MSM_8x25_ADC_DEV_ID;
- adc_dev->nchans = MSM_8x25_CHAN_ID;
- }
- adc_dev->transl.hwmon_dev_idx = i;
- adc_dev->transl.hwmon_start = hwmon_cntr;
- adc_dev->transl.hwmon_end = hwmon_cntr + adc_dev->nchans - 1;
- hwmon_cntr += adc_dev->nchans;
- rc = msm_rpc_adc_device_init_hwmon(pdev, adc_dev);
- if (rc)
- goto dev_init_err;
- }
- return 0;
- dev_init_err:
- msm_rpc_adc_teardown_devices(pdev);
- return rc;
- }
- static int __devinit msm_rpc_adc_init(struct platform_device *pdev1)
- {
- struct msm_adc_drv *msm_adc = msm_adc_drv;
- struct platform_device *pdev = msm_adc->pdev;
- struct msm_adc_platform_data *pdata = pdev->dev.platform_data;
- int rc = 0;
- dev_dbg(&pdev->dev, "msm_rpc_adc_init called\n");
- if (!pdata) {
- dev_err(&pdev->dev, "no platform data?\n");
- return -EINVAL;
- }
- mutex_init(&msm_adc->prop_lock);
- rc = daldevice_attach(MSM_ADC_DALRPC_DEVICEID,
- MSM_ADC_DALRPC_PORT_NAME,
- MSM_ADC_DALRPC_CPU,
- &msm_adc->dev_h);
- if (rc) {
- dev_err(&pdev->dev, "Cannot attach to dal device\n");
- return rc;
- }
- dev_dbg(&pdev->dev, "Attach to dal device Succeeded\n");
- rc = msm_rpc_adc_device_init(pdev);
- if (rc) {
- dev_err(&pdev->dev, "msm_adc_dev_init failed\n");
- goto err_cleanup;
- }
- init_waitqueue_head(&msm_adc->rpc_total_outst_wait);
- atomic_set(&msm_adc->rpc_online, 1);
- atomic_set(&msm_adc->rpc_total_outst, 0);
- epm_init = true;
- pr_info("msm_adc successfully registered\n");
- return 0;
- err_cleanup:
- msm_rpc_adc_teardown_devices(pdev);
- return rc;
- }
- /*
- * Process the deferred job
- */
- void msm_adc_wq_work(struct work_struct *work)
- {
- struct adc_properties *adc_properties;
- struct adc_conv_slot *slot = container_of(work,
- struct adc_conv_slot, work);
- uint32_t idx = slot->conv.result.chan;
- struct msm_adc_platform_data *pdata =
- msm_adc_drv->pdev->dev.platform_data;
- struct msm_adc_channels *channel = &pdata->channel[idx];
- int32_t adc_code;
- switch (slot->adc_request) {
- case START_OF_CONV:
- channel->adc_access_fn->adc_select_chan_and_start_conv(
- channel->adc_dev_instance, slot);
- break;
- case END_OF_CONV:
- adc_properties = channel->adc_access_fn->adc_get_properties(
- channel->adc_dev_instance);
- if (channel->adc_access_fn->adc_read_adc_code)
- channel->adc_access_fn->adc_read_adc_code(
- channel->adc_dev_instance, &adc_code);
- if (channel->chan_processor)
- channel->chan_processor(adc_code, adc_properties,
- &slot->chan_properties, &slot->conv.result);
- /* Intentionally a fall thru here. Calibraton does not need
- to perform channel processing, etc. However, both
- end of conversion and end of calibration requires the below
- fall thru code to be executed. */
- case END_OF_CALIBRATION:
- /* for blocking requests, signal complete */
- if (slot->blocking)
- complete(&slot->comp);
- else {
- struct msm_client_data *client = slot->client;
- mutex_lock(&client->lock);
- if (slot->adc_request == END_OF_CONV) {
- list_add(&slot->list, &client->complete_list);
- client->num_complete++;
- }
- client->num_outstanding--;
- /*
- * if the client release has been invoked and this is call
- * corresponds to the last request, then signal release
- * to complete.
- */
- if (slot->client->online == 0 &&
- client->num_outstanding == 0)
- wake_up_interruptible_all(&client->outst_wait);
- mutex_unlock(&client->lock);
- wake_up_interruptible_all(&client->data_wait);
- atomic_dec(&msm_adc_drv->total_outst);
- /* verify driver remove has not been invoked */
- if (atomic_read(&msm_adc_drv->online) == 0 &&
- atomic_read(&msm_adc_drv->total_outst) == 0)
- wake_up_interruptible_all(
- &msm_adc_drv->total_outst_wait);
- if (slot->compk) /* Kernel space request */
- complete(slot->compk);
- if (slot->adc_request == END_OF_CALIBRATION)
- channel->adc_access_fn->adc_restore_slot(
- channel->adc_dev_instance, slot);
- }
- break;
- case START_OF_CALIBRATION: /* code here to please code reviewers
- to satisfy silly compiler warnings */
- break;
- }
- }
- static struct sensor_device_attribute msm_adc_curr_in_attr =
- SENSOR_ATTR(NULL, S_IRUGO, msm_adc_show_curr, NULL, 0);
- static int __devinit msm_adc_init_hwmon(struct platform_device *pdev,
- struct msm_adc_drv *msm_adc)
- {
- struct msm_adc_platform_data *pdata = pdev->dev.platform_data;
- struct msm_adc_channels *channel = pdata->channel;
- int i, rc, num_chans = pdata->num_chan_supported;
- if (!channel)
- return -EINVAL;
- msm_adc->sens_attr = kzalloc(num_chans *
- sizeof(struct sensor_device_attribute), GFP_KERNEL);
- if (!msm_adc->sens_attr) {
- dev_err(&pdev->dev, "Unable to allocate memory\n");
- rc = -ENOMEM;
- goto hwmon_err_sens;
- }
- for (i = 0; i < num_chans; i++) {
- msm_adc_curr_in_attr.index = i;
- msm_adc_curr_in_attr.dev_attr.attr.name = channel[i].name;
- memcpy(&msm_adc->sens_attr[i], &msm_adc_curr_in_attr,
- sizeof(msm_adc_curr_in_attr));
- rc = device_create_file(&pdev->dev,
- &msm_adc->sens_attr[i].dev_attr);
- if (rc) {
- dev_err(&pdev->dev, "device_create_file failed for "
- "dal dev %s\n",
- channel[i].name);
- goto hwmon_err_sens;
- }
- }
- return 0;
- hwmon_err_sens:
- kfree(msm_adc->sens_attr);
- return rc;
- }
- static struct platform_driver msm_adc_rpcrouter_remote_driver = {
- .probe = msm_rpc_adc_init,
- .driver = {
- .name = MSM_ADC_DALRPC_PORT_NAME,
- .owner = THIS_MODULE,
- },
- };
- static int __devinit msm_adc_probe(struct platform_device *pdev)
- {
- struct msm_adc_platform_data *pdata = pdev->dev.platform_data;
- struct msm_adc_drv *msm_adc;
- int rc = 0;
- if (!pdata) {
- dev_err(&pdev->dev, "no platform data?\n");
- return -EINVAL;
- }
- msm_adc = kzalloc(sizeof(struct msm_adc_drv), GFP_KERNEL);
- if (!msm_adc) {
- dev_err(&pdev->dev, "Unable to allocate memory\n");
- return -ENOMEM;
- }
- platform_set_drvdata(pdev, msm_adc);
- msm_adc_drv = msm_adc;
- msm_adc->pdev = pdev;
- if (pdata->target_hw == MSM_8x60 || pdata->target_hw == FSM_9xxx) {
- rc = msm_adc_init_hwmon(pdev, msm_adc);
- if (rc) {
- dev_err(&pdev->dev, "msm_adc_dev_init failed\n");
- goto err_cleanup;
- }
- }
- msm_adc->hwmon = hwmon_device_register(&pdev->dev);
- if (IS_ERR(msm_adc->hwmon)) {
- dev_err(&pdev->dev, "hwmon_device_register failed\n");
- rc = PTR_ERR(msm_adc->hwmon);
- goto err_cleanup;
- }
- msm_adc->misc.name = MSM_ADC_DRIVER_NAME;
- msm_adc->misc.minor = MISC_DYNAMIC_MINOR;
- msm_adc->misc.fops = &msm_adc_fops;
- if (misc_register(&msm_adc->misc)) {
- dev_err(&pdev->dev, "Unable to register misc device!\n");
- goto err_cleanup;
- }
- init_waitqueue_head(&msm_adc->total_outst_wait);
- atomic_set(&msm_adc->online, 1);
- atomic_set(&msm_adc->total_outst, 0);
- msm_adc->wq = create_singlethread_workqueue("msm_adc");
- if (!msm_adc->wq)
- goto err_cleanup;
- if (pdata->num_adc > 0) {
- if (pdata->target_hw == MSM_8x60)
- platform_driver_register(
- &msm_adc_rpcrouter_remote_driver);
- else
- msm_rpc_adc_init(pdev);
- }
- conv_first_request = true;
- pr_info("msm_adc successfully registered\n");
- return 0;
- err_cleanup:
- msm_adc_teardown(pdev);
- return rc;
- }
- static int __devexit msm_adc_remove(struct platform_device *pdev)
- {
- int rc;
- struct msm_adc_drv *msm_adc = platform_get_drvdata(pdev);
- atomic_set(&msm_adc->online, 0);
- atomic_set(&msm_adc->rpc_online, 0);
- misc_deregister(&msm_adc->misc);
- hwmon_device_unregister(msm_adc->hwmon);
- msm_adc->hwmon = NULL;
- /*
- * We may still have outstanding transactions in flight that have not
- * completed. Make sure they're completed before tearing down.
- */
- rc = wait_event_interruptible(msm_adc->total_outst_wait,
- atomic_read(&msm_adc->total_outst) == 0);
- if (rc) {
- pr_err("%s: wait_event_interruptible failed rc = %d\n",
- __func__, rc);
- return rc;
- }
- rc = wait_event_interruptible(msm_adc->rpc_total_outst_wait,
- atomic_read(&msm_adc->rpc_total_outst) == 0);
- if (rc) {
- pr_err("%s: wait_event_interruptible failed rc = %d\n",
- __func__, rc);
- return rc;
- }
- msm_adc_teardown(pdev);
- pr_info("msm_adc unregistered\n");
- return 0;
- }
- static struct platform_driver msm_adc_driver = {
- .probe = msm_adc_probe,
- .remove = __devexit_p(msm_adc_remove),
- .driver = {
- .name = MSM_ADC_DRIVER_NAME,
- .owner = THIS_MODULE,
- },
- };
- static int __init msm_adc_init(void)
- {
- return platform_driver_register(&msm_adc_driver);
- }
- module_init(msm_adc_init);
- static void __exit msm_adc_exit(void)
- {
- platform_driver_unregister(&msm_adc_driver);
- }
- module_exit(msm_adc_exit);
- MODULE_DESCRIPTION("MSM ADC Driver");
- MODULE_ALIAS("platform:msm_adc");
- MODULE_LICENSE("GPL v2");
- MODULE_VERSION("0.1");
|