ADC platfrom day65
5. ADC
5.1 代码
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <mach/gpio-nrs.h>
#include <mach/gpio.h>
#include <linux/miscdevice.h>
#include <asm/ioctl.h>
#include <linux/interrupt.h>
#include <linux/irqreturn.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/workqueue.h>#define DEV_NAME "adc"
static wait_queue_head_t wq;
static int condition = 0;
static struct work_struct work;
#define ADCCON 0x58000000
#define ADCDAT0 0x5800000C
#define CLKCON 0x4C00000C
static volatile unsigned long * adccon;
static volatile unsigned long * adcdat0;
static volatile unsigned long * clkcon;#define MAGIC_NUM 'x'
#define SET_CHANNEL 0x20
#define CMD_SET_CHANNEL _IO(MAGIC_NUM, SET_CHANNEL)static inline void init_adc(void)
{*adccon = (1 << 14) | (49 << 6);
}static inline int adc_set_channel(unsigned char channel)
{if(channel > 7)return -EINVAL;*adccon &= ~(0x7 << 3);*adccon |= ((channel & 0x7) << 3); return 0;
}static inline void adc_start(void)
{*adccon |= (1 << 0);
}static inline unsigned short adc_read(void)
{unsigned short data = *adcdat0 & 0x3ff;return data;
}static void work_func(struct work_struct *work)
{condition = 1;wake_up_interruptible(&wq);printk("task_func ....\n");
}static irqreturn_t adc_handler(int irq_num, void * dev)
{schedule_work(&work);return IRQ_HANDLED;
}static int open(struct inode * node, struct file * file)
{init_adc();printk("adc open ...\n");return 0;
}static ssize_t read(struct file * file, char __user * buf, size_t len, loff_t * offset)
{unsigned short data = 0;printk("adc read start...\n");condition = 0;adc_start();wait_event_interruptible(wq, condition);data = adc_read();copy_to_user(buf, &data, sizeof(data));printk("adc read end...\n");return sizeof(data);
}static ssize_t write(struct file * file, const char __user * buf, size_t len, loff_t * offset)
{printk("adc write ...\n");return 0;
}static long ioctl(struct file * file, unsigned int cmd, unsigned long arg)
{int ret = 0;switch(cmd){case CMD_SET_CHANNEL :ret = adc_set_channel((unsigned char)arg);break;default:ret = -EINVAL;break;}return ret;
}static int close(struct inode * node, struct file * file)
{printk("adc close ...\n");return 0;
}static struct file_operations fops =
{.owner = THIS_MODULE,.open = open,.read = read,.write = write,.unlocked_ioctl = ioctl,.release = close
};static struct miscdevice misc =
{.minor = MISC_DYNAMIC_MINOR,.name = DEV_NAME,.fops = &fops
};static int __init adc_init(void)
{int ret = misc_register(&misc);if(ret < 0)goto err_misc_register;ret = request_irq(IRQ_ADC, adc_handler, IRQF_DISABLED, "irq_adc", NULL);if(ret < 0)goto err_request_irq;init_waitqueue_head(&wq);INIT_WORK(&work, work_func);adccon = ioremap(ADCCON, 4);adcdat0 = ioremap(ADCDAT0, 4);clkcon = ioremap(CLKCON, 4);*clkcon |= (1 << 15);printk("adc_init ....\n");return ret;
err_request_irq:disable_irq(IRQ_ADC);free_irq(IRQ_ADC, NULL);printk("request_irq failed\n");return ret;err_misc_register:misc_deregister(&misc);printk("misc_register faikey\n");return ret;
}static void __exit key_exit(void)
{iounmap(adcdat0);iounmap(adccon);disable_irq(IRQ_ADC);free_irq(IRQ_ADC, NULL);misc_deregister(&misc);printk("adc_exit ....\n");
}module_init(adc_init);
module_exit(key_exit);
MODULE_LICENSE("GPL");
5.2用户空间和内核空间的配对
//内核空间
#define MAGIC_NUM 'x'
#define SET_CHANNEL 0x20
#define CMD_SET_CHANNEL _IO(MAGIC_NUM, SET_CHANNEL)static long ioctl(struct file * file, unsigned int cmd, unsigned long arg)
{int ret = 0;switch(cmd){case CMD_SET_CHANNEL :ret = adc_set_channel((unsigned char)arg);break;default:ret = -EINVAL;break;}return ret;
}//用户空间unsigned short data;while(1){ioctl(fd,CMD_SET_CHANNEL,0);read(fd,&data,sizeof data);float v = data *3.3 / 1024;printf("0---------data = %d v = %3.2f \n",data,v);sleep(1);ioctl(fd,CMD_SET_CHANNEL,1);read(fd,&data,sizeof data);v = data *3.3 / 1024;printf("1----------data = %d v = %3.2f \n",data,v);sleep(1);ioctl(fd,CMD_SET_CHANNEL,100);read(fd,&data,sizeof data);v = data *3.3 / 1024;printf("err--------data = %d v = %3.2f \n",data,v);sleep(1);}
十:platform
1. bus_type
struct bus_type {const char *name;struct bus_attribute *bus_attrs;struct device_attribute *dev_attrs;struct driver_attribute *drv_attrs;int (*match)(struct device *dev, struct device_driver *drv);int (*uevent)(struct device *dev, struct kobj_uevent_env *env);int (*probe)(struct device *dev);int (*remove)(struct device *dev);void (*shutdown)(struct device *dev);int (*suspend)(struct device *dev, pm_message_t state);int (*resume)(struct device *dev);const struct dev_pm_ops *pm;struct bus_type_private *p;
};
2. platform
总线
匹配先看匹配表,因为这个是独一无二的,名字可能会重名 extern struct bus_type platform_bus_type;
extern struct device platform_bus;struct platform_device {const char * name; //匹配的名字int id;struct device dev;u32 num_resources; //设备资源数量struct resource * resource; //设备资源struct platform_device_id *id_entry; //匹配表/* arch specific additions */struct pdev_archdata archdata;
};//resource
struct resource {resource_size_t start; //起始位置resource_size_t end; //终点位置const char *name; //eg:gpbunsigned long flags; //对应的类型 struct resource *parent, *sibling, *child;
};
extern int platform_driver_register(struct platform_driver *);
extern void platform_driver_unregister(struct platform_driver *);struct platform_driver {int (*probe)(struct platform_device *); //注册 device和driver都要加载完成后执行int (*remove)(struct platform_device *); //销毁 device和driver,任意一个要卸载后执行void (*shutdown)(struct platform_device *);int (*suspend)(struct platform_device *, pm_message_t state);int (*resume)(struct platform_device *);struct device_driver driver;struct platform_device_id *id_table; //匹配表
};-------
//driver
struct device_driver {const char *name; //根据名字匹配struct bus_type *bus;struct module *owner;const char *mod_name; /* used for built-in modules */bool suppress_bind_attrs; /* disables bind/unbind via sysfs */int (*probe) (struct device *dev);int (*remove) (struct device *dev);void (*shutdown) (struct device *dev);int (*suspend) (struct device *dev, pm_message_t state);int (*resume) (struct device *dev);const struct attribute_group **groups;const struct dev_pm_ops *pm;struct driver_private *p;
};
3.代码
先加载device,再加载driver //如果不用release的话
//driver
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <mach/gpio-nrs.h>
#include <mach/gpio.h>
#include <linux/miscdevice.h>
#include <asm/ioctl.h>
#include <linux/interrupt.h>
#include <linux/irqreturn.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/workqueue.h>
#include <linux/platform_device.h>#define DEV_NAME "adc"
static wait_queue_head_t wq;
static int condition = 0;
static struct work_struct work;
static volatile unsigned long * adccon;
static volatile unsigned long * adcdat0;
static volatile unsigned long * clkcon;#define MAGIC_NUM 'x'
#define SET_CHANNEL 0x20
#define CMD_SET_CHANNEL _IO(MAGIC_NUM, SET_CHANNEL)static inline void init_adc(void)
{*adccon = (1 << 14) | (49 << 6);
}static inline int adc_set_channel(unsigned char channel)
{if(channel > 7)return -EINVAL;*adccon &= ~(0x7 << 3);*adccon |= ((channel & 0x7) << 3); return 0;
}static inline void adc_start(void)
{*adccon |= (1 << 0);
}static inline unsigned short adc_read(void)
{unsigned short data = *adcdat0 & 0x3ff;return data;
}static void work_func(struct work_struct *work)
{condition = 1;wake_up_interruptible(&wq);printk("task_func ....\n");
}static irqreturn_t adc_handler(int irq_num, void * dev)
{schedule_work(&work);return IRQ_HANDLED;
}static int open(struct inode * node, struct file * file)
{init_adc();printk("adc open ...\n");return 0;
}static ssize_t read(struct file * file, char __user * buf, size_t len, loff_t * offset)
{unsigned short data = 0;printk("adc read start...\n");condition = 0;adc_start();wait_event_interruptible(wq, condition);data = adc_read();copy_to_user(buf, &data, sizeof(data));printk("adc read end...\n");return sizeof(data);
}static ssize_t write(struct file * file, const char __user * buf, size_t len, loff_t * offset)
{printk("adc write ...\n");return 0;
}static long ioctl(struct file * file, unsigned int cmd, unsigned long arg)
{int ret = 0;switch(cmd){case CMD_SET_CHANNEL :ret = adc_set_channel((unsigned char)arg);break;default:ret = -EINVAL;break;}return ret;
}static int close(struct inode * node, struct file * file)
{printk("adc close ...\n");return 0;
}static struct file_operations fops =
{.owner = THIS_MODULE,.open = open,.read = read,.write = write,.unlocked_ioctl = ioctl,.release = close
};static struct miscdevice misc =
{.minor = MISC_DYNAMIC_MINOR,.name = DEV_NAME,.fops = &fops
};static int probe(struct platform_device * pdev)
{int ret = misc_register(&misc);if(ret < 0)goto err_misc_register;ret = request_irq(pdev->resource[3].start, adc_handler, IRQF_DISABLED, "irq_adc", NULL);if(ret < 0)goto err_request_irq;init_waitqueue_head(&wq);INIT_WORK(&work, work_func);adccon = ioremap(pdev->resource[0].start, pdev->resource[0].end - pdev->resource[0].start + 1);adcdat0 = ioremap(pdev->resource[1].start, pdev->resource[1].end - pdev->resource[1].start + 1);clkcon = ioremap(pdev->resource[2].start, pdev->resource[2].end - pdev->resource[2].start + 1);*clkcon |= (1 << 15);printk("adc probe ....\n");return ret;
err_request_irq:disable_irq(pdev->resource[3].start);free_irq(pdev->resource[3].start, NULL);printk("request_irq failed\n");return ret;err_misc_register:misc_deregister(&misc);printk("misc_register failed\n");return ret; return 0;
}static int remove(struct platform_device * pdev)
{iounmap(clkcon);iounmap(adcdat0);iounmap(adccon);disable_irq(pdev->resource[3].start);free_irq(pdev->resource[3].start, NULL);misc_deregister(&misc);printk("adc remove ....\n");return 0;
}static struct platform_driver drv =
{.probe = probe,.remove = remove,.driver = {.name = DEV_NAME}
};static int __init adc_driver_init(void)
{int ret = platform_driver_register(&drv);if(ret < 0){platform_driver_unregister(&drv); return ret;}printk("adc_driver_init ...\n");return 0;
}static void __exit adc_driver_exit(void)
{platform_driver_unregister(&drv); printk("adc_driver_exit ...\n");
}module_init(adc_driver_init);
module_exit(adc_driver_exit);
MODULE_LICENSE("GPL");
//device
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <asm/io.h>
#include <mach/gpio-nrs.h>
#include <mach/gpio.h>
#include <linux/ioport.h>
#include <linux/platform_device.h>
#include <mach/irqs.h>#define DEV_NAME "adc"
#define ADCCON 0x58000000
#define ADCDAT0 0x5800000C
#define CLKCON 0x4C00000C
#define ADC_IRQ_NUM IRQ_ADCstatic struct resource res[4] =
{[0] = {.start = ADCCON,.end = ADCCON + 4 - 1,.name = "adccon",.flags = IORESOURCE_IO },[1] = {.start = ADCDAT0,.end = ADCDAT0 + 4 - 1,.name = "adcdat0",.flags = IORESOURCE_IO},[2] = {.start = CLKCON,.end = CLKCON + 4 - 1,.name = "clkcon",.flags = IORESOURCE_IO },[3] = {.start = ADC_IRQ_NUM,.end = ADC_IRQ_NUM,.name = "irq_adc",.flags = IORESOURCE_IRQ}
};static void release(struct device *dev){}static struct platform_device pdev =
{.name = DEV_NAME,.id = -1,.dev = {.release = release },.num_resources = sizeof(res) / sizeof(res[0]),.resource = res,
};static int __init adc_device_init(void)
{int ret = platform_device_register(&pdev);if(ret < 0){platform_device_unregister(&pdev); return ret;}printk("adc_device_init ...\n");return 0;
}static void __exit adc_device_exit(void)
{platform_device_unregister(&pdev); printk("adc_device_exit ...\n");
}module_init(adc_device_init);
module_exit(adc_device_exit);
MODULE_LICENSE("GPL");