新手上路
- 积分
- 49
- 金钱
- 49
- 注册时间
- 2017-9-27
- 在线时间
- 6 小时
|
楼主 |
发表于 2022-6-25 11:52:07
|
显示全部楼层
数码管驱动代码:
- #include <asm/io.h>
- #include <asm/uaccess.h>
- #include <linux/cdev.h>
- #include <linux/fs.h>
- #include <linux/of.h>
- #include <linux/of_address.h>
- #include <linux/of_irq.h>
- #include <linux/gpio/consumer.h>
- #include <linux/interrupt.h>
- #include <linux/module.h>
- #include <linux/platform_device.h>
- #include <linux/slab.h>
- #define _BV(n) (1ull << (n))
- #define GPT_CR_EN_24M _BV(10)
- #define GPT_CR_CLKSRC_Pos 6
- #define GPT_CR_ENMOD _BV(1)
- #define GPT_CR_EN _BV(0)
- #define GPT_SR_OF1 _BV(0)
- #define GPT_IR_OF1IE _BV(0)
- struct imx6ull_gpt
- {
- u32 CR;
- u32 PR;
- u32 SR;
- u32 IR;
- u32 OCR1;
- u32 OCR2;
- u32 OCR3;
- u32 ICR1;
- u32 ICR2;
- u32 CNT;
- };
- struct test_data
- {
- struct gpio_descs *gpios;
- dev_t devid;
- struct cdev cdev;
- struct class *class;
- struct device *device;
-
- struct imx6ull_gpt __iomem *GPT2;
- u32 __iomem (*CCGR)[2];
- unsigned int irq;
-
- int number;
- int number_bit;
- int number_tmp;
- };
- struct test_file
- {
- struct test_data *data;
- char msg[50];
- int len;
- };
- static int test_remove(struct platform_device *pdev);
- static const u8 seg_table[] = {0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90};
- static int test_open(struct inode *inode, struct file *file)
- {
- struct test_file *p;
-
- p = kzalloc(sizeof(struct test_file), GFP_KERNEL);
- if (p == NULL)
- return -ENOMEM;
- file->private_data = p;
-
- p->data = container_of(inode->i_cdev, struct test_data, cdev);
- snprintf(p->msg, sizeof(p->msg), "Number: %d\nCounter: %d\nGPT2->SR=0x%02x\n", p->data->number, readl(&p->data->GPT2->CNT), readl(&p->data->GPT2->SR));
- p->len = strlen(p->msg);
- return 0;
- }
- static int test_release(struct inode *inode, struct file *file)
- {
- if (file->private_data != NULL)
- kfree(file->private_data);
- return 0;
- }
- static ssize_t test_read(struct file *file, char __user *buf, size_t size, loff_t *off)
- {
- int ret;
- struct test_file *p = file->private_data;
-
- if (*off + size > p->len)
- size = p->len - *off;
- if (size > 0)
- {
- ret = copy_to_user(buf, p->msg, size);
- if (ret != 0)
- return -EFAULT;
- *off += size;
- }
- return size;
- }
- static ssize_t test_write(struct file *file, const char __user *buf, size_t size, loff_t *off)
- {
- char ch;
- char *s;
- int ret;
- struct test_file *p = file->private_data;
-
- if (size == 0)
- return -EFAULT;
- get_user(ch, &buf[size - 1]);
- if (ch != '\r' && ch != '\n')
- return -EFAULT;
-
- s = kzalloc(size, GFP_KERNEL);
- if (s == NULL)
- return -ENOMEM;
- ret = copy_from_user(s, buf, size - 1);
- if (ret != 0)
- {
- kfree(s);
- return -EFAULT;
- }
-
- p->data->number = simple_strtol(s, NULL, 10);
- if (p->data->number < 0)
- p->data->number = 0;
- else if (p->data->number > 99999999)
- p->data->number = 99999999;
- kfree(s);
- return size;
- }
- static long test_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
- {
- return 0;
- }
- static const struct file_operations test_fops = {
- .owner = THIS_MODULE,
- .open = test_open,
- .release = test_release,
- .read = test_read,
- .write = test_write,
- .unlocked_ioctl = test_unlocked_ioctl
- };
- static void ser_in(struct test_data *p, u8 data)
- {
- int i;
-
- for (i = 0; i < 8; i++)
- {
- gpiod_set_value(p->gpios->desc[0], 0);
- if (data & 0x80)
- gpiod_set_value(p->gpios->desc[2], 1);
- else
- gpiod_set_value(p->gpios->desc[2], 0);
- gpiod_set_value(p->gpios->desc[0], 1);
- data <<= 1;
- }
- }
- static void par_out(struct test_data *p)
- {
- gpiod_set_value(p->gpios->desc[1], 0);
- gpiod_set_value(p->gpios->desc[1], 1);
- }
- static irqreturn_t gpt2_irqhandler(int irq, void *dev)
- {
- struct test_data *p = dev;
-
- // 74HC595扫描数码管
- if (p->number_bit == 0)
- p->number_tmp = p->number;
- else
- p->number_tmp /= 10;
- ser_in(p, seg_table[p->number_tmp % 10]);
- ser_in(p, 1 << p->number_bit);
- par_out(p);
-
- p->number_bit++;
- if (p->number_bit == 8)
- p->number_bit = 0;
-
- writel(GPT_SR_OF1, &p->GPT2->SR); // 写1清除中断
- return IRQ_HANDLED;
- }
- static int test_probe(struct platform_device *pdev)
- {
- int ret;
- struct device_node *node;
- struct resource res;
- struct test_data *data;
-
- /* 创建结构体 */
- pr_err("test_probe(0x%p);\n", pdev);
- data = devm_kzalloc(&pdev->dev, sizeof(struct test_data), GFP_KERNEL);
- if (data == NULL)
- {
- pr_err("devm_kzalloc() failed\n");
- return -ENOMEM;
- }
- platform_set_drvdata(pdev, data);
-
- /* 创建设备 */
- ret = alloc_chrdev_region(&data->devid, 100, 1, "mydeviceid");
- if (ret != 0)
- {
- pr_err("alloc_chrdev_region() failed\n");
- return ret;
- }
- pr_err("Device ID: %d,%d\n", MAJOR(data->devid), MINOR(data->devid));
- cdev_init(&data->cdev, &test_fops);
- ret = cdev_add(&data->cdev, data->devid, 1);
- if (ret != 0)
- {
- pr_err("cdev_add() failed\n");
- goto err;
- }
-
- /* 创建设备文件 */
- data->class = class_create(THIS_MODULE, "classname");
- if (IS_ERR(data->class))
- {
- pr_err("class_create() failed\n");
- ret = PTR_ERR(data->class);
- goto err;
- }
- data->device = device_create(data->class, NULL, data->devid, NULL, "devicename");
- if (IS_ERR(data->device))
- {
- pr_err("device_create() failed\n");
- ret = PTR_ERR(data->device);
- goto err;
- }
-
- /* 获取GPIO端口 */
- data->gpios = devm_gpiod_get_array(&pdev->dev, NULL, GPIOD_OUT_LOW);
- if (IS_ERR(data->gpios))
- {
- pr_err("devm_gpiod_get_array() failed\n");
- ret = PTR_ERR(data->gpios);
- goto err;
- }
-
- /* 配置GPT2定时器 */
- data->number = 20220605; // 数码管默认显示的数字
- data->GPT2 = ioremap(0x020e8000, sizeof(struct imx6ull_gpt)); // 映射GPT2外设的寄存器
- data->CCGR = ioremap(0x020c4068, sizeof(*data->CCGR)); // 映射CCM外设的CCGR0~1寄存器
- if (data->GPT2 == NULL || data->CCGR == NULL)
- {
- // 寄存器映射失败
- pr_err("ioremap() failed\n");
- ret = -EFAULT;
- goto err;
- }
- writel(readl(&data->CCGR[0]) | _BV(24), &data->CCGR[0]); // 在CCM中使能GPT2的时钟: gpt2_bus_clk_enable=1
- pr_err("CCGR0=0x%08x\n", readl(&data->CCGR[0]));
- pr_err("CCGR1=0x%08x\n", readl(&data->CCGR[1]));
- pr_err("GPT2->CR=0x%08x\n", readl(&data->GPT2->CR));
-
- writel(GPT_IR_OF1IE, &data->GPT2->IR); // 开中断
- pr_err("GPT2->IR=0x%02x\n", readl(&data->GPT2->IR));
- pr_err("GPT2->SR=0x%02x\n", readl(&data->GPT2->SR));
-
- // 循环遍历设备树中所有指定compatible的节点
- // node使用完毕后必须调用of_find_compatible_node或of_node_put释放掉
- node = NULL;
- while ((node = of_find_compatible_node(node, NULL, "fsl,imx6ul-gpt")) != NULL)
- {
- ret = of_address_to_resource(node, 0, &res);
- pr_err("name=%s, full_name=%s, start=0x%08x\n", node->name, node->full_name, res.start);
- if (ret == 0 && res.start == 0x020e8000)
- {
- // 已找到gpt2节点
- data->irq = irq_of_parse_and_map(node, 0); // 解析interrupts属性, 得到linux中断号
- pr_err("found gpt2 node: irq=%d\n", data->irq);
- of_node_put(node);
- break;
- }
- }
- if (data->irq == 0)
- {
- // 没有找到gpt2节点, 或者解析gpt2节点的interrupts属性失败
- pr_err("no IRQ found\n");
- ret = -ENODEV;
- goto err;
- }
- // 请求中断
- ret = devm_request_irq(&pdev->dev, data->irq, gpt2_irqhandler, IRQF_TRIGGER_RISING, "gpt2_int", data);
- if (ret != 0)
- {
- pr_err("request_irq() failed! ret=%d\n", ret);
- goto err;
- }
-
- writel(999, &data->GPT2->OCR1); // 计数最大值
- writel(249, &data->GPT2->PR); // 分频系数
- writel(GPT_SR_OF1, &data->GPT2->SR); // 打开定时器前必须清除中断, 以免中断线一直为高, 没有边沿出现, 无法进入中断函数
- writel((1 << GPT_CR_CLKSRC_Pos) | GPT_CR_EN, &data->GPT2->CR); // 开始定时
- pr_err("GPT2->CR=0x%08x\n", readl(&data->GPT2->CR));
- return 0;
-
- err:
- test_remove(pdev);
- return ret;
- }
- static int test_remove(struct platform_device *pdev)
- {
- struct test_data *data;
-
- pr_err("test_remove(0x%p);\n", pdev);
- data = platform_get_drvdata(pdev);
- if (data != NULL)
- {
- if (data->GPT2 != NULL)
- {
- pr_err("GPT2->CR=0x%08x\n", readl(&data->GPT2->CR));
- writel(readl(&data->GPT2->CR) & ~GPT_CR_EN, &data->GPT2->CR); // 停止定时
- pr_err("GPT2->CR=0x%08x\n", readl(&data->GPT2->CR));
- iounmap(data->GPT2);
- }
- if (data->CCGR != NULL)
- iounmap(data->CCGR);
- if (data->device != NULL && !IS_ERR(data->device))
- device_destroy(data->class, data->devid);
- if (data->class != NULL && !IS_ERR(data->class))
- class_destroy(data->class);
- cdev_del(&data->cdev);
- unregister_chrdev_region(data->devid, 1);
- platform_set_drvdata(pdev, NULL);
- }
- return 0;
- }
- static const struct of_device_id test_match_ids[] = {
- {.compatible = "mygpiotest,myboard2"},
- {}
- };
- MODULE_DEVICE_TABLE(of, test_match_ids);
- static struct platform_driver test_driver = {
- .driver = {
- .name = "mytestdriver",
- .of_match_table = of_match_ptr(test_match_ids)
- },
- .probe = test_probe,
- .remove = test_remove
- };
- module_platform_driver(test_driver);
- MODULE_AUTHOR("Oct1158");
- MODULE_LICENSE("GPL");
复制代码 |
|