buzzer_platform_dev.c
/*
* linux-3.10.27
* arm-linux-gcc-4.5.1
*
* @ buzzer device (base platform device driver)
*/
#include <linux/module.h>
#include <linux/init.h> /* module_init, ... */
#include <linux/kernel.h> /* everything */
#include <linux/cdev.h> /* cdev_init, ... */
#include <linux/fs.h> /* file_operations, */
#include <linux/device.h> /* class_create,... */
#include <linux/platform_device.h>
#include <linux/slab.h> /* kmalloc, ... */
#include <asm/io.h> /* ioremap,... */
#include <linux/gpio.h>
static struct resource buzzer_res[] =
{
{
.start = 0xE02000A0, // gpd0_0 GPD0CON
.end = 0xE02000C0,
.flags = IORESOURCE_MEM,
},
};
static void buzzer_dev_release(struct device *dev)
{
pr_info("%s called.\n", __func__);
}
static struct platform_device buzzer_dev =
{
.name = "smart210,buzzer",
.dev = {
.release = buzzer_dev_release,
},
.resource = buzzer_res,
.num_resources = ARRAY_SIZE(buzzer_res),
};
static int __init buzzer_platform_dev_init(void)
{
int ret = 0;
pr_info("buzzer platform dev init.\n");
ret = platform_device_register(&buzzer_dev);
if(ret){
pr_err("platform register err.\n");
}
return ret;
}
static void __exit buzzer_platform_dev_exit(void)
{
pr_info("buzzer platform dev exit.\n");
platform_device_unregister(&buzzer_dev);
}
module_init(buzzer_platform_dev_init);
module_exit(buzzer_platform_dev_exit);
MODULE_LICENSE("GPL");
buzzer_platform_drv.c
/*
* linux-3.10.27
* arm-linux-gcc-4.5.1
*
* @ buzzer driver (base platform device driver)
*/
#include <linux/module.h>
#include <linux/init.h> /* module_init, ... */
#include <linux/kernel.h> /* everything */
#include <linux/cdev.h> /* cdev_init, ... */
#include <linux/fs.h> /* file_operations, */
#include <linux/device.h> /* class_create,... */
#include <linux/platform_device.h>
#include <linux/slab.h> /* kmalloc, ... */
#include <linux/io.h> /* ioremap,... */
#include <linux/uaccess.h> /* copy_from_user, ... */
struct buzzer_gpio
{
unsigned long con;
unsigned long dat;
unsigned long pud;
unsigned long drv;
unsigned long conpdn;
unsigned long pudpdn;
};
#define DEF_DEV_NAME "myBuzzer"
#define DEF_MAJOR 0
struct priv_data
{
char *name;
int major;
dev_t dev;
struct cdev *cdev;
struct class *cls;
struct buzzer_gpio *base;
};
static struct priv_data *priv_data;
static int smart210_buzzer_open (struct inode *inode, struct file *pfile)
{
pr_info("%s called.\n", __func__);
/* set GPD0_0 as output */
priv_data->base->con |= (1 << 0);
return 0;
}
static int smart210_buzzer_close (struct inode *inode, struct file *pfile)
{
pr_info("%s called.\n", __func__);
return 0;
}
static ssize_t smart210_buzzer_write (struct file *file,
const char __user *usrbuff, size_t len, loff_t *offset)
{
char recvbuf[8] = {0};
char cmd, opt;
if(copy_from_user(recvbuf, usrbuff, len)){
return -EINVAL;
}
cmd = recvbuf[0];
opt = recvbuf[1];
printk(KERN_NOTICE "cmd : %d opt : %d \n", cmd, opt);
if(opt > 0)
return EINVAL;
switch(cmd){
case 0:
priv_data->base->dat &= ~(1 << 0);
break;
case 1:
priv_data->base->dat |= (1 << 0);
break;
default:
break;
}
return 0;
}
const struct file_operations fops =
{
.owner = THIS_MODULE,
.open = smart210_buzzer_open,
.release = smart210_buzzer_close,
.write = smart210_buzzer_write,
};
static ssize_t buzzer_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
pr_info("%s called .\n", __func__);
return 0;
}
static ssize_t buzzer_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
char value = 0;
if(sscanf(buf, "%d", &value)){
if(value)
priv_data->base->dat |= (1 << 0);
else
priv_data->base->dat &= ~(1 << 0);
}
return 0;
}
static DEVICE_ATTR(buzzer, 0644, buzzer_show, buzzer_store);
static int buzzer_platform_drv_probe(struct platform_device *pdev)
{
int ret = 0;
pr_info("%s called .\n", __func__);
priv_data = devm_kzalloc(&pdev->dev, sizeof(struct priv_data), GFP_KERNEL);
if(!priv_data){
pr_err("no mem.\n");
return -ENOMEM;
}
priv_data->name = DEF_DEV_NAME;
priv_data->major = DEF_MAJOR;
if(priv_data->major){
priv_data->dev = MKDEV(priv_data->major, 0);
ret = register_chrdev_region(priv_data->dev, 1, priv_data->name);
}else{
ret = alloc_chrdev_region(&priv_data->dev, 1, 1, priv_data->name);
priv_data->major = MAJOR(priv_data->dev);
}
if(ret){
pr_err("chrdev register err.\n");
return ret;
}
/* add cdev */
priv_data->cdev = cdev_alloc();
if(!priv_data->cdev){
pr_err("cdev alloc err.\n");
goto err0;
}
cdev_init(priv_data->cdev, &fops);
priv_data->cdev->owner = THIS_MODULE;
priv_data->cdev->ops = &fops;
cdev_add(priv_data->cdev, priv_data->dev, 1);
/* add class */
priv_data->cls = class_create(THIS_MODULE, priv_data->name);
if(!priv_data->cls){
pr_err("class create err.\n");
goto err1;
}
device_create(priv_data->cls, NULL, priv_data->dev, NULL, priv_data->name);
priv_data->base = (struct buzzer_gpio *)devm_ioremap(&pdev->dev, pdev->resource->start, 0x20);
if(!priv_data->base){
pr_err("ioremap err.\n");
goto err2;
}
/*
* create /sys/bus/platform/devices/smart210,buzzer.0
* echo 1 > buzzer ; echo 0 > buzzer
*/
device_create_file(&pdev->dev, &dev_attr_buzzer);
return 0;
err2:
device_destroy(priv_data->cls, priv_data->dev);
class_destroy(priv_data->cls);
err1:
cdev_del(priv_data->cdev);
err0:
unregister_chrdev_region(priv_data->dev, 1);
return -EINVAL;
}
static int buzzer_platform_drv_remove(struct platform_device *pdev)
{
pr_info("%s called .\n", __func__);
/* remove /sys/bus/platform/devices/smart210,buzzer.0 */
device_remove_file(&pdev->dev, &dev_attr_buzzer);
device_destroy(priv_data->cls, priv_data->dev);
class_destroy(priv_data->cls);
cdev_del(priv_data->cdev);
unregister_chrdev_region(priv_data->dev, 1);
return 0;
}
const struct of_device_id buzzer_ids[] =
{
{.compatible = "smart210,buzzer"},
{}
};
static struct platform_driver buzzer_platform_drv = {
.driver = {
.name = "smart210,buzzer",
.of_match_table = buzzer_ids,
},
.probe = buzzer_platform_drv_probe,
.remove = buzzer_platform_drv_remove,
};
static int __init buzzer_platform_drv_init(void)
{
int ret = 0;
pr_info("%s called .\n", __func__);
ret = platform_driver_register(&buzzer_platform_drv);
if(ret){
pr_err("platform driver register err.\n");
}
return ret;
}
static void __exit buzzer_platform_drv_exit(void)
{
pr_info("%s called .\n", __func__);
platform_driver_unregister(&buzzer_platform_drv);
}
module_init(buzzer_platform_drv_init);
module_exit(buzzer_platform_drv_exit);
MODULE_LICENSE("GPL");