/** * @file testdrv.c * @brief Test module for the initialisation of the McASP in * interrupt mode. */ #ifdef DEBUG #define pr_fmt(fmt) "DRV1: [%s():%d]: " fmt,__func__,__LINE__ #define dev_fmt(fmt) "[%s():%d]: " fmt,__func__,__LINE__ #else #define pr_fmt(fmt) "DRV1: " fmt #define dev_fmt(fmt) fmt #endif #include #include #include #include #include #include #include #include /* * AM335x Register dfinition for McASP controller */ #define AM335x_MCASP_REV_REG 0x00 /* Revision Identification Register */ #define AM335x_MCASP_PWRIDLE_REG 0x04 /* Power Idle SYSCONFIG Register */ #define AM335x_MCASP_PFUNC_REG 0x10 /* Pin Function Register */ #define AM335x_MCASP_PDIR_REG 0x14 /* Pin Direction Register */ #define AM335x_MCASP_PDOUT_REG 0x18 /* Pin Data Output Register */ #define AM335x_MCASP_PDIN_REG 0x1C /* Pin Data Input Register */ #define AM335x_MCASP_PDCLR_REG 0x20 /* Pin Data Clear Register */ #define AM335x_MCASP_GBLCTL_REG 0x44 /* Global Control Register */ #define AM335x_MCASP_AMUTE_REG 0x48 /* Audio Mute Control Register */ #define AM335x_MCASP_DLBCTL_REG 0x4C /* Digital Loopback Control Register */ #define AM335x_MCASP_DITCTL_REG 0x50 /* DIT Mode Control Register */ #define AM335x_MCASP_RGBLCTL_REG 0x60 /* Receiver Global Control Register */ #define AM335x_MCASP_RMASK_REG 0x64 /* Receive Format Unit Bit Mask Register*/ #define AM335x_MCASP_RFMT_REG 0x68 /* Receive Bit Stream Format Register */ #define AM335x_MCASP_AFSRCTL_REG 0x6C /* Receive Frame Sync Control Register */ #define AM335x_MCASP_ACLKRCTL_REG 0x70 /* Receive Clock Control Register */ #define AM335x_MCASP_AHCLKRCTL_REG 0x74 /* Receive Hi.-Freq. Clock Control Reg. */ #define AM335x_MCASP_RTDM_REG 0x78 /* Receive TDM Time Slot 0-31 Register */ #define AM335x_MCASP_RINTCTL_REG 0x7C /* Receiver Interrupt Control Register */ #define AM335x_MCASP_RSTAT_REG 0x80 /* Receiver Status Register */ #define AM335x_MCASP_RSLOT_REG 0x84 /* Current Receive TDM Time Slot Reg. */ #define AM335x_MCASP_RCLKCHK_REG 0x88 /* Receive Clock Check Control Register */ #define AM335x_MCASP_REVTCTL_REG 0x8C /* Receiver DMA Event Control Register */ #define AM335x_MCASP_XGBLCTL_REG 0xA0 /* Transmitter Global Control Register */ #define AM335x_MCASP_XMASK_REG 0xA4 /* Transmit Format Unit Bit Mask Reg. */ #define AM335x_MCASP_XFMT_REG 0xA8 /* Transmit Bit Stream Format Register */ #define AM335x_MCASP_AFSXCTL_REG 0xAC /* Transmit Frame Sync Control Register */ #define AM335x_MCASP_ACLKXCTL_REG 0xB0 /* Transmit Clock Control Register */ #define AM335x_MCASP_AHCLKXCTL_REG 0xB4 /* Transmit Hi.-Freq. Clk. Control Reg. */ #define AM335x_MCASP_XTDM_REG 0xB8 /* Transmit TDM Time Slot 0-31 Register */ #define AM335x_MCASP_XINTCTL_REG 0xBC /* Transmitter Interrupt Control Reg. */ #define AM335x_MCASP_XSTAT_REG 0xC0 /* Transmitter Status Register */ #define AM335x_MCASP_XSLOT_REG 0xC4 /* Current Transmit TDM Time Slot Reg. */ #define AM335x_MCASP_XCLKCHK_REG 0xC8 /* Transmit Clock Check Control Reg. */ #define AM335x_MCASP_XEVTCTL_REG 0xCC /* Transmitter DMA Event Control Reg. */ /* 100h to 114h | DITCSRA_0 to DITCSRA_5 | Left (Even TDM Time Slot) Channel Status Registers (DIT Mode) 118h to 12Ch | DITCSRB_0 to DITCSRB_5 | Right (Odd TDM Time Slot) Channel Status Registers (DIT Mode) 130h to 144h | DITUDRA_0 to DITUDRA_5 | Left (Even TDM Time Slot) Channel User Data Registers (DIT Mode) 148h to 15Ch | DITUDRB_0 to DITUDRB_5 | Right (Odd TDM Time Slot) Channel User Data Registers (DIT Mode) */ #define AM335x_MCASP_SRCTL_BASE 0x180 /* Serializer Control Registers 0..5 */ #define AM335x_MCASP_SRCTL_REG(n) (AM335x_MCASP_SRCTL_BASE + (n << 2)) #define AM335x_MCASP_XBUF_BASE 0x200 /* Transmit Buffer Reg.for Serializers */ #define AM335x_MCASP_XBUF_REG(n) (AM335x_MCASP_XBUF_BASE + (n << 2)) #define AM335x_MCASP_RBUF_BASE 0x280 /* Receive Buffer Reg.for Serializers */ #define AM335x_MCASP_RBUF_REG(n) (AM335x_MCASP_RBUF_BASE + (n << 2)) #define AM335x_MCASP_WFIFOCTL_REG 0x1000 /* Write FIFO Control Register */ #define AM335x_MCASP_WFIFOSTS_REG 0x1004 /* Write FIFO Status Register */ #define AM335x_MCASP_RFIFOCTL_REG 0x1008 /* Read FIFO Control Register */ #define AM335x_MCASP_RFIFOSTS_REG 0x100C /* Read FIFO Status Register */ struct testdrv1 { void __iomem *mcasp_base; struct miscdevice mdev; }; #define REG_DUMP(str, offs, dev) printk(KERN_INFO " [0x%04x] "str, offs, mcasp_get_reg(dev, offs)) static inline u32 mcasp_get_reg(void __iomem *base, u32 offset) { return (u32)__raw_readl(base + offset); } void mcasp_dump_registers(void __iomem *base) { int i; pr_info("Dump McASP register information:"); REG_DUMP("REV = 0x%08x\n", AM335x_MCASP_REV_REG, base); REG_DUMP("PWRIDLESYSCONFIG = 0x%08x\n", AM335x_MCASP_PWRIDLE_REG, base); REG_DUMP("PFUNC = 0x%08x\n", AM335x_MCASP_PFUNC_REG, base); REG_DUMP("PDIR = 0x%08x\n", AM335x_MCASP_PDIR_REG, base); REG_DUMP("PDOUT = 0x%08x\n", AM335x_MCASP_PDOUT_REG, base); REG_DUMP("PDIN = 0x%08x\n", AM335x_MCASP_PDIN_REG, base); REG_DUMP("PDCLR = 0x%08x\n", AM335x_MCASP_PDCLR_REG, base); REG_DUMP("GBLCTL = 0x%08x\n", AM335x_MCASP_GBLCTL_REG, base); REG_DUMP("AMUTE = 0x%08x\n", AM335x_MCASP_AMUTE_REG, base); REG_DUMP("DLBCTL = 0x%08x\n", AM335x_MCASP_DLBCTL_REG, base); REG_DUMP("DITCTL = 0x%08x\n", AM335x_MCASP_DITCTL_REG, base); REG_DUMP("RGBLCTL = 0x%08x\n", AM335x_MCASP_RGBLCTL_REG, base); REG_DUMP("RMASK = 0x%08x\n", AM335x_MCASP_RMASK_REG, base); REG_DUMP("RFMT = 0x%08x\n", AM335x_MCASP_RFMT_REG, base); REG_DUMP("AFSRCTL = 0x%08x\n", AM335x_MCASP_AFSRCTL_REG, base); REG_DUMP("ACLKRCTL = 0x%08x\n", AM335x_MCASP_ACLKRCTL_REG, base); REG_DUMP("AHCLKRCTL = 0x%08x\n", AM335x_MCASP_AHCLKRCTL_REG, base); REG_DUMP("RTDM = 0x%08x\n", AM335x_MCASP_RTDM_REG, base); REG_DUMP("RINTCTL = 0x%08x\n", AM335x_MCASP_RINTCTL_REG, base); REG_DUMP("RSTAT = 0x%08x\n", AM335x_MCASP_RSTAT_REG, base); REG_DUMP("RSLOT = 0x%08x\n", AM335x_MCASP_RSLOT_REG, base); REG_DUMP("RCLKCHK = 0x%08x\n", AM335x_MCASP_RCLKCHK_REG, base); REG_DUMP("REVTCTL = 0x%08x\n", AM335x_MCASP_REVTCTL_REG, base); REG_DUMP("XGBLCTL = 0x%08x\n", AM335x_MCASP_XGBLCTL_REG, base); REG_DUMP("XMASK = 0x%08x\n", AM335x_MCASP_XMASK_REG, base); REG_DUMP("XFMT = 0x%08x\n", AM335x_MCASP_XFMT_REG, base); REG_DUMP("AFSXCTL = 0x%08x\n", AM335x_MCASP_AFSXCTL_REG, base); REG_DUMP("ACLKXCTL = 0x%08x\n", AM335x_MCASP_ACLKXCTL_REG, base); REG_DUMP("AHCLKXCTL = 0x%08x\n", AM335x_MCASP_AHCLKXCTL_REG, base); REG_DUMP("XTDM = 0x%08x\n", AM335x_MCASP_XTDM_REG, base); REG_DUMP("XINTCTL = 0x%08x\n", AM335x_MCASP_XINTCTL_REG, base); REG_DUMP("XSTAT = 0x%08x\n", AM335x_MCASP_XSTAT_REG, base); REG_DUMP("XSLOT = 0x%08x\n", AM335x_MCASP_XSLOT_REG, base); REG_DUMP("XCLKCHK = 0x%08x\n", AM335x_MCASP_XCLKCHK_REG, base); REG_DUMP("XEVTCTL = 0x%08x\n", AM335x_MCASP_XEVTCTL_REG, base); for(i = 0; i <= 5; i++) { printk(KERN_INFO " [0x%04x] SRCTL_%d = 0x%08x\n", AM335x_MCASP_SRCTL_REG(i), i, mcasp_get_reg(base, AM335x_MCASP_SRCTL_REG(i))); } for(i = 0; i <= 5; i++) { printk(KERN_INFO " [0x%04x] XBUF_%d = 0x%08x\n", AM335x_MCASP_XBUF_REG(i), i, mcasp_get_reg(base, AM335x_MCASP_XBUF_REG(i))); } for(i = 0; i <= 5; i++) { printk(KERN_INFO " [0x%04x] RBUF_%d = 0x%08x\n", AM335x_MCASP_RBUF_REG(i), i, mcasp_get_reg(base, AM335x_MCASP_RBUF_REG(i))); } REG_DUMP("WFIFOCTL = 0x%08x\n", AM335x_MCASP_WFIFOCTL_REG, base); REG_DUMP("WFIFOSTS = 0x%08x\n", AM335x_MCASP_WFIFOSTS_REG, base); REG_DUMP("RFIFOCTL = 0x%08x\n", AM335x_MCASP_RFIFOCTL_REG, base); REG_DUMP("RFIFOSTS = 0x%08x\n", AM335x_MCASP_RFIFOSTS_REG, base); } static int drv_mdev_open(struct inode* inode, struct file* file) { struct testdrv1 *drv = container_of(file->private_data, struct testdrv1, mdev); pr_info("misc device open called ...\n"); dev_info(drv->mdev.this_device, "memory for driver data found at 0x%08x\n", (unsigned int)drv); dev_info(drv->mdev.this_device, "virtual address for McASP registers base mapped at 0x%08X.\n", (unsigned int)drv->mcasp_base); mcasp_dump_registers(drv->mcasp_base); return 0; } static int drv_mdev_close(struct inode* inode, struct file* file) { pr_info("misc device close called ...\n"); return 0; } static long drv_mdev_ioctl(struct file* file, unsigned int cmd, unsigned long arg) { pr_info("misc device ioctl called ...\n"); return 0; } static const struct file_operations drv_ops = { .owner = THIS_MODULE, .open = drv_mdev_open, .release = drv_mdev_close, .unlocked_ioctl = drv_mdev_ioctl, }; static int drv_probe(struct platform_device* pdev) { int ret; struct testdrv1 *drv; pr_info("probe function called.\n"); if(!pdev->dev.platform_data && !pdev->dev.of_node) { dev_err(&pdev->dev, "no platform data supplied\n"); return -EINVAL; } dev_info(&pdev->dev, "platform data supplied\n"); drv = devm_kzalloc(&pdev->dev, sizeof(struct testdrv1), GFP_KERNEL); if(!drv) { dev_err(&pdev->dev, "memory allocation failed\n"); return -ENOMEM; } dev_info(&pdev->dev, "memory for driver allocated at 0x%08x\n", (unsigned int)drv); platform_set_drvdata(pdev, drv); /* init miscdevice */ drv->mdev.minor = MISC_DYNAMIC_MINOR; drv->mdev.name = "testdrv"; drv->mdev.fops = &drv_ops; ret = misc_register(&drv->mdev); if(ret) { dev_err(&pdev->dev, "create misc device failed\n"); return -ENODEV; } dev_info(&pdev->dev, "misc device created\n"); drv->mcasp_base = devm_platform_ioremap_resource_byname(pdev, "mpu"); if(IS_ERR(drv->mcasp_base)) { dev_err(&pdev->dev, "get virtual address for McASP registers base failed.\n"); return PTR_ERR(drv->mcasp_base); } dev_info(&pdev->dev, "virtual address for McASP registers base mapped at 0x%08X.\n", (unsigned int)drv->mcasp_base); mcasp_dump_registers(drv->mcasp_base); return 0; } static int drv_remove(struct platform_device* pdev) { struct testdrv1 *drv = (struct testdrv1*)platform_get_drvdata(pdev); pr_info("remove function called.\n"); misc_deregister(&drv->mdev); return 0; } /* list of devices supported by the driver */ static const struct of_device_id mcasp_ids[] = { { .compatible = "ti,am33xx-mcasp-audio", .data = NULL, }, {} }; MODULE_DEVICE_TABLE(of, mcasp_ids); /* Platform driver information */ struct platform_driver test_driver = { .probe = drv_probe, .remove = drv_remove, .driver = { .name = "testdrv1", .of_match_table = mcasp_ids, .owner = THIS_MODULE } }; /** The LKM initialization function. * * @return returns 0 if successful. */ static int testdrv1_init(void) { pr_info("module init...\n"); platform_driver_register(&test_driver); return 0; } module_init(testdrv1_init); /** The LKM cleanup function. */ static void testdrv1_exit(void) { pr_info("module release ...\n"); platform_driver_unregister(&test_driver); } module_exit(testdrv1_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Eduard Fuchs"); MODULE_DESCRIPTION("Testdrv1 for inspect McASP interface.");