一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

adc.c

 guitarhua 2011-12-26
/* linux/arch/arm/plat-s3c64xx/adc.c
 *
 * 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.
 *
 * 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.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 *
 * Copyright (c) 2004 Arnaud Patard <arnaud.patard@rtp-net.org>
 * iPAQ H1940 touchscreen support
 *
 * ChangeLog
 *
 * 2004-09-05: Herbert P?tzl <herbert@13thfloor.at>
 * - added clock (de-)allocation code
 *
 * 2005-03-06: Arnaud Patard <arnaud.patard@rtp-net.org>
 *      - h1940_ -> s3c24xx (this driver is now also used on the n30
 *        machines :P)
 *      - Debug messages are now enabled with the config option
 *        TOUCHSCREEN_S3C_DEBUG
 *      - Changed the way the value are read
 *      - Input subsystem should now work
 *      - Use ioremap and readl/writel
 *
 * 2005-03-23: Arnaud Patard <arnaud.patard@rtp-net.org>
 *      - Make use of some undocumented features of the touchscreen
 *        controller
 *
 */


#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/init.h>
#include <linux/serio.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/miscdevice.h>
#include <linux/clk.h>
#include <linux/mutex.h>

#include <asm/io.h>
#include <asm/irq.h>
#include <mach/hardware.h>
#include <asm/uaccess.h>

#include <plat/regs-adc.h>
#include <plat/adc.h>
#include <mach/irqs.h>

#define ADC_MINOR 131
#define ADC_INPUT_PIN   _IOW('S', 0x0c, unsigned long)

#define ADC_WITH_TOUCHSCREEN

static struct clk *adc_clock;

static void __iomem *base_addr;
static int adc_port =  0;
struct s3c_adc_mach_info *plat_data;


#ifdef ADC_WITH_TOUCHSCREEN
static DEFINE_MUTEX(adc_mutex);

static unsigned long data_for_ADCCON;
static unsigned long data_for_ADCTSC;

static void s3c_adc_save_SFR_on_ADC(void)
{
data_for_ADCCON = readl(base_addr + S3C_ADCCON);
data_for_ADCTSC = readl(base_addr + S3C_ADCTSC);
}

static void s3c_adc_restore_SFR_on_ADC(void)
{
writel(data_for_ADCCON, base_addr + S3C_ADCCON);
writel(data_for_ADCTSC, base_addr + S3C_ADCTSC);
}
#else
static struct resource *adc_mem;
#endif

static int s3c_adc_open(struct inode *inode, struct file *file)
{
printk(KERN_INFO " s3c_adc_open() entered\n");
return 0;
}

unsigned int s3c_adc_convert(void)
{
unsigned int adc_return = 0;
unsigned long data0;
unsigned long data1;

writel(readl(base_addr + S3C_ADCCON) | S3C_ADCCON_SELMUX(adc_port), base_addr + S3C_ADCCON);

udelay(10);

writel(readl(base_addr + S3C_ADCCON) | S3C_ADCCON_ENABLE_START, base_addr + S3C_ADCCON);

do {
data0 = readl(base_addr + S3C_ADCCON);
} while(!(data0 & S3C_ADCCON_ECFLG));

data1 = readl(base_addr + S3C_ADCDAT0);

if (plat_data->resolution == 12)
adc_return = data1 & S3C_ADCDAT0_XPDATA_MASK_12BIT;
else
adc_return = data1 & S3C_ADCDAT0_XPDATA_MASK;

return adc_return;
}


int s3c_adc_get(struct s3c_adc_request *req)
{
unsigned adc_channel = req->channel;
int adc_value_ret = 0;

adc_value_ret = s3c_adc_convert();

req->callback(adc_channel,req->param, adc_value_ret);

return 0;
}
EXPORT_SYMBOL(s3c_adc_get);


static ssize_t
s3c_adc_read(struct file *file, char __user * buffer,
size_t size, loff_t * pos)
{
int  adc_value = 0;

printk(KERN_INFO " s3c_adc_read() entered\n");

#ifdef ADC_WITH_TOUCHSCREEN
        mutex_lock(&adc_mutex);
s3c_adc_save_SFR_on_ADC();
#endif

adc_value = s3c_adc_convert();

#ifdef ADC_WITH_TOUCHSCREEN
s3c_adc_restore_SFR_on_ADC();
mutex_unlock(&adc_mutex);
#endif

printk(KERN_INFO " Converted Value: %03d\n", adc_value);

if (copy_to_user(buffer, &adc_value, sizeof(unsigned int))) {
return -EFAULT;
}
return sizeof(unsigned int);
}


static int s3c_adc_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{

       printk(KERN_INFO " s3c_adc_ioctl(cmd:: %d) entered\n", cmd);

switch (cmd) {
case ADC_INPUT_PIN:
adc_port = (unsigned int) arg;

if (adc_port >= 4)
printk(" %d is already reserved for TouchScreen\n", adc_port);
return 0;

              default:
return -ENOIOCTLCMD;
}
}

static struct file_operations s3c_adc_fops = {
.owner = THIS_MODULE,
.read = s3c_adc_read,
.open = s3c_adc_open,
.ioctl = s3c_adc_ioctl,
};

static struct miscdevice s3c_adc_miscdev = {
.minor = ADC_MINOR,
.name = "adc",
.fops = &s3c_adc_fops,
};

static struct s3c_adc_mach_info *s3c_adc_get_platdata(struct device *dev)
{
if(dev->platform_data != NULL)
{
return (struct s3c_adc_mach_info*) dev->platform_data;
} else {
printk(KERN_INFO "No ADC platform data \n");
return 0;
}
}

/*
 * The functions for inserting/removing us as a module.
 */

static int __init s3c_adc_probe(struct platform_device *pdev)
{
struct resource *res;
struct device *dev;
int ret;
int size;

res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
dev = &pdev->dev;

if(res == NULL){
dev_err(dev,"no memory resource specified\n");
return -ENOENT;
}

size = (res->end - res->start) + 1;

#if !defined(ADC_WITH_TOUCHSCREEN)
adc_mem = request_mem_region(res->start, size, pdev->name);
if(adc_mem == NULL){
dev_err(dev, "failed to get memory region\n");
ret = -ENOENT;
goto err_req;
}
#endif

base_addr = ioremap(res->start, size);
if(base_addr ==  NULL){
dev_err(dev,"fail to ioremap() region\n");
ret = -ENOENT;
goto err_map;
}

adc_clock = clk_get(&pdev->dev, "adc");

if(IS_ERR(adc_clock)){
dev_err(dev,"failed to fine ADC clock source\n");
ret = PTR_ERR(adc_clock);
goto err_clk;
}

clk_enable(adc_clock);

/* read platform data from device struct */
plat_data = s3c_adc_get_platdata(&pdev->dev);

if ((plat_data->presc & 0xff) > 0)
writel(S3C_ADCCON_PRSCEN | S3C_ADCCON_PRSCVL(plat_data->presc & 0xff), base_addr + S3C_ADCCON);
else
writel(0, base_addr + S3C_ADCCON);

/* Initialise registers */
if ((plat_data->delay & 0xffff) > 0)
writel(plat_data->delay & 0xffff, base_addr + S3C_ADCDLY);

if (plat_data->resolution == 12)
writel(readl(base_addr + S3C_ADCCON) | S3C_ADCCON_RESSEL_12BIT, base_addr + S3C_ADCCON);

ret = misc_register(&s3c_adc_miscdev);
if (ret) {
printk (KERN_ERR "cannot register miscdev on minor=%d (%d)\n",
ADC_MINOR, ret);
goto err_clk;
}

printk(KERN_INFO "S5P64XX ADC driver successfully probed\n");

return 0;

err_clk:
clk_disable(adc_clock);
clk_put(adc_clock);

err_map:
iounmap(base_addr);

#if !defined(ADC_WITH_TOUCHSCREEN)
err_req:
release_resource(adc_mem);
kfree(adc_mem);
#endif

return ret;
}


static int s3c_adc_remove(struct platform_device *dev)
{
printk(KERN_INFO "s3c_adc_remove() of ADC called !\n");
return 0;
}

#ifdef CONFIG_PM
static unsigned int adccon, adctsc, adcdly;

static int s3c_adc_suspend(struct platform_device *dev, pm_message_t state)
{
adccon = readl(base_addr + S3C_ADCCON);
adctsc = readl(base_addr + S3C_ADCTSC);
adcdly = readl(base_addr + S3C_ADCDLY);

clk_disable(adc_clock);

return 0;
}

static int s3c_adc_resume(struct platform_device *pdev)
{
clk_enable(adc_clock);

writel(adccon, base_addr + S3C_ADCCON);
writel(adctsc, base_addr + S3C_ADCTSC);
writel(adcdly, base_addr + S3C_ADCDLY);

return 0;
}
#else
#define s3c_adc_suspend NULL
#define s3c_adc_resume  NULL
#endif

static struct platform_driver s3c_adc_driver = {
       .probe          = s3c_adc_probe,
       .remove         = s3c_adc_remove,
       .suspend        = s3c_adc_suspend,
       .resume         = s3c_adc_resume,
       .driver = {
.owner = THIS_MODULE,
.name = "s3c-adc",
},
};

static char banner[] __initdata = KERN_INFO "S3C64XX ADC driver, (c) 2008 Samsung Electronics\n";

int __init s3c_adc_init(void)
{
printk(banner);
return platform_driver_register(&s3c_adc_driver);
}

void __exit s3c_adc_exit(void)
{
platform_driver_unregister(&s3c_adc_driver);
}

module_init(s3c_adc_init);
module_exit(s3c_adc_exit);

MODULE_AUTHOR("boyko.lee@samsung.com");
MODULE_DESCRIPTION("S3C64XX ADC driver");
MODULE_LICENSE("GPL");

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多

    国产户外勾引精品露出一区| 色无极东京热男人的天堂| 日本女优一区二区三区免费| 99久久人妻中文字幕| 欧美日韩国产福利在线观看| 夜夜嗨激情五月天精品| 丰满熟女少妇一区二区三区| 日本欧美在线一区二区三区| 99久久人妻精品免费一区| 色一情一乱一区二区三区码| 99久久精品午夜一区二| 欧美一区二区日韩一区二区| 黄片三级免费在线观看| 午夜福利视频偷拍91| 中文字幕免费观看亚洲视频| 日韩成人动画在线观看| 麻豆国产精品一区二区| 亚洲国产性生活高潮免费视频| 欧美av人人妻av人人爽蜜桃| 91欧美亚洲精品在线观看| 国产精品视频第一第二区| 办公室丝袜高跟秘书国产| 国产午夜福利一区二区| 熟女高潮一区二区三区| 日韩熟妇人妻一区二区三区 | 国产精品免费不卡视频| 日韩欧美中文字幕av| 欧美不卡一区二区在线视频| 中文字幕欧美视频二区| 日本少妇中文字幕不卡视频 | 欧美午夜一级艳片免费看| 91超频在线视频中文字幕| 国产又粗又硬又大又爽的视频| 超碰在线播放国产精品| 99日韩在线视频精品免费| 我想看亚洲一级黄色录像| 日韩少妇人妻中文字幕| 91偷拍视频久久精品| 亚洲中文字幕日韩在线| 久久精品国产99国产免费| 欧美视频在线观看一区|