/* * GSC3280 SoC adc Controller Driver * * Copyright (C) 2013 BLX IC Design Corp.,Ltd. * Author: Davied, apple_guet@126.com * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * */ #include #include #include #include #include #include #include #include #include #include #include #include "adc.h" #ifdef CONFIG_GSC_ADC_CORE_DEBUG #define DBG(msg...) do { \ printk(KERN_INFO msg); \ } while (0) #else #define DBG(msg...) do { } while(0) #endif struct class *adc_class; static DEFINE_IDR(adc_idr); static DEFINE_MUTEX(adc_idr_lock); static void adc_device_release(struct device *dev) { struct adc_core_dev *adc = to_adc_device(dev); mutex_lock(&adc_idr_lock); idr_remove(&adc_idr, adc->id); mutex_unlock(&adc_idr_lock); kfree(adc); } /** * adc_device_register - register w/ ADC class * @dev: the device to register * * adc_device_unregister() must be called when the class device is no * longer needed. * * Returns the pointer to the new struct class device. */ struct adc_core_dev *adc_device_register(const char *name, struct device *dev, const struct adc_class_ops *ops, struct module *owner) { struct adc_core_dev *adc; int id, err; if (idr_pre_get(&adc_idr, GFP_KERNEL) == 0) { err = -ENOMEM; goto exit; } mutex_lock(&adc_idr_lock); err = idr_get_new(&adc_idr, NULL, &id); mutex_unlock(&adc_idr_lock); if (err < 0) goto exit; id = id & MAX_ID_MASK; adc= kzalloc(sizeof(struct adc_core_dev), GFP_KERNEL); if (adc == NULL) { err = -ENOMEM; goto exit_idr; } adc->id = id; adc->ops = ops; adc->owner = owner; adc->dev.parent = dev; adc->dev.class = adc_class; adc->dev.release = adc_device_release; mutex_init(&adc->ops_lock); strlcpy(adc->name, name, ADC_CORE_NAME_SIZE); dev_set_name(&adc->dev, "adc%d", id); adc_dev_prepare(adc); err = device_register(&adc->dev); if (err) { put_device(&adc->dev); goto exit_kfree; } adc_dev_add_device(adc); adc_sysfs_add_device(adc); adc_proc_add_device(adc); dev_info(dev, "adc core: registered %s as %s\n", adc->name, dev_name(&adc->dev)); return adc; exit_kfree: kfree(adc); exit_idr: mutex_lock(&adc_idr_lock); idr_remove(&adc_idr, id); mutex_unlock(&adc_idr_lock); exit: dev_err(dev, "adc core: unable to register %s, err = %d\n", name, err); return ERR_PTR(err); } EXPORT_SYMBOL_GPL(adc_device_register); /** * adc_device_unregister - removes the previously registered ADC class device * * @adc: the ADC class device to destroy */ void adc_device_unregister(struct adc_core_dev *adc) { if (get_device(&adc->dev) != NULL) { mutex_lock(&adc->ops_lock); adc_sysfs_del_device(adc); adc_dev_del_device(adc); adc_proc_del_device(adc); device_unregister(&adc->dev); adc->ops = NULL; mutex_unlock(&adc->ops_lock); put_device(&adc->dev); } } EXPORT_SYMBOL_GPL(adc_device_unregister); static int __init gsc_adc_init(void) { adc_class = class_create(THIS_MODULE, "adc"); if (IS_ERR(adc_class)) { printk(KERN_ERR "%s: couldn't create class\n", __FILE__); return PTR_ERR(adc_class); } //adc_class->suspend = adcSuspend; //adc_class->resume = adcResume; adc_dev_init(); adc_sysfs_init(adc_class); writel(0x01, (volatile unsigned int *)0xbc04a0ac); //enable ts and adc return 0; } static void __exit gsc_adc_exit(void) { adc_dev_exit(); class_destroy(adc_class); idr_destroy(&adc_idr); } subsys_initcall(gsc_adc_init); module_exit(gsc_adc_exit); MODULE_AUTHOR("Davied"); MODULE_DESCRIPTION("gsc3280 spi0 adc Driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:gsc3280-spi0 adc");