ckfwq/linux-3.0.4/drivers/spi/adc/adc-core.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");