171 lines
3.9 KiB
C
171 lines
3.9 KiB
C
/*
|
|
* 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 <linux/module.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/list.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/err.h>
|
|
#include <linux/clk.h>
|
|
#include <linux/idr.h>
|
|
#include <linux/io.h>
|
|
#include <linux/adc-core.h>
|
|
|
|
#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<apple_guet@126.com>");
|
|
MODULE_DESCRIPTION("gsc3280 spi0 adc Driver");
|
|
MODULE_LICENSE("GPL");
|
|
MODULE_ALIAS("platform:gsc3280-spi0 adc");
|
|
|