From patchwork Tue Mar 8 13:57:40 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Subhasish Ghosh X-Patchwork-Id: 618261 Received: from bear.ext.ti.com (bear.ext.ti.com [192.94.94.41]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id p28Dg4ld008662 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Tue, 8 Mar 2011 13:42:27 GMT Received: from dlep36.itg.ti.com ([157.170.170.91]) by bear.ext.ti.com (8.13.7/8.13.7) with ESMTP id p28Dg3lI001615 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO) for ; Tue, 8 Mar 2011 07:42:03 -0600 Received: from linux.omap.com (localhost [127.0.0.1]) by dlep36.itg.ti.com (8.13.8/8.13.8) with ESMTP id p28Dg3FL018244 for ; Tue, 8 Mar 2011 07:42:03 -0600 (CST) Received: from linux.omap.com (localhost [127.0.0.1]) by linux.omap.com (Postfix) with ESMTP id E871C8062A for ; Tue, 8 Mar 2011 07:42:01 -0600 (CST) X-Original-To: davinci-linux-open-source@linux.davincidsp.com Delivered-To: davinci-linux-open-source@linux.davincidsp.com Received: from dflp51.itg.ti.com (dflp51.itg.ti.com [128.247.22.94]) by linux.omap.com (Postfix) with ESMTP id 7A58B80626 for ; Tue, 8 Mar 2011 07:41:54 -0600 (CST) Received: from red.ext.ti.com (localhost [127.0.0.1]) by dflp51.itg.ti.com (8.13.7/8.13.7) with ESMTP id p28DfsJE022339 for ; Tue, 8 Mar 2011 07:41:54 -0600 (CST) Received: from psmtp.com (na3sys009amx168.postini.com [74.125.149.94]) by red.ext.ti.com (8.13.7/8.13.7) with SMTP id p28DfrmY019441 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO) for ; Tue, 8 Mar 2011 07:41:53 -0600 Received: from source ([209.85.210.45]) (using TLSv1) by na3sys009amx168.postini.com ([74.125.148.10]) with SMTP; Tue, 08 Mar 2011 13:41:53 GMT Received: by pzk3 with SMTP id 3so1174249pzk.4 for ; Tue, 08 Mar 2011 05:41:52 -0800 (PST) Received: by 10.143.20.17 with SMTP id x17mr4340054wfi.154.1299591712542; Tue, 08 Mar 2011 05:41:52 -0800 (PST) Received: from localhost ([122.166.13.232]) by mx.google.com with ESMTPS id w19sm1010314wfd.20.2011.03.08.05.41.42 (version=TLSv1/SSLv3 cipher=OTHER); Tue, 08 Mar 2011 05:41:51 -0800 (PST) From: Subhasish Ghosh To: davinci-linux-open-source@linux.davincidsp.com Subject: [PATCH v3 1/7] mfd: add pruss mfd driver. Date: Tue, 8 Mar 2011 19:27:40 +0530 Message-Id: <1299592667-21367-2-git-send-email-subhasish@mistralsolutions.com> X-Mailer: git-send-email 1.7.2.3 In-Reply-To: <1299592667-21367-1-git-send-email-subhasish@mistralsolutions.com> References: <1299592667-21367-1-git-send-email-subhasish@mistralsolutions.com> X-pstn-neptune: 0/0/0.00/0 X-pstn-levels: (S:99.90000/99.90000 CV:99.9000 FC:95.5390 LC:95.5390 R:95.9108 P:95.9108 M:97.0282 C:98.6951 ) X-pstn-settings: 2 (0.5000:0.0750) s cv GT3 gt2 gt1 r p m c X-pstn-addresses: from [db-null] Cc: sachi@mistralsolutions.com, Samuel Ortiz , Subhasish Ghosh , open list , m-watkins@ti.com, linux-arm-kernel@lists.infradead.org X-BeenThere: davinci-linux-open-source@linux.davincidsp.com X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: davinci-linux-open-source-bounces+patchwork-davinci=patchwork.kernel.org@linux.davincidsp.com Errors-To: davinci-linux-open-source-bounces+patchwork-davinci=patchwork.kernel.org@linux.davincidsp.com X-Greylist: Sender succeeded STARTTLS authentication, not delayed by milter-greylist-4.2.6 (demeter1.kernel.org [140.211.167.41]); Tue, 08 Mar 2011 13:42:27 +0000 (UTC) diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index fd01836..6c437df 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -81,6 +81,16 @@ config MFD_DM355EVM_MSP boards. MSP430 firmware manages resets and power sequencing, inputs from buttons and the IR remote, LEDs, an RTC, and more. +config MFD_DA8XX_PRUSS + tristate "Texas Instruments DA8XX PRUSS support" + depends on ARCH_DAVINCI && ARCH_DAVINCI_DA850 + select MFD_CORE + help + This driver provides support api's for the programmable + realtime unit (PRU) present on TI's da8xx processors. It + provides basic read, write, config, enable, disable + routines to facilitate devices emulated on it. + config HTC_EGPIO bool "HTC EGPIO support" depends on GENERIC_HARDIRQS && GPIOLIB && ARM diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index a54e2c7..670d6b0 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_HTC_PASIC3) += htc-pasic3.o obj-$(CONFIG_HTC_I2CPLD) += htc-i2cpld.o obj-$(CONFIG_MFD_DAVINCI_VOICECODEC) += davinci_voicecodec.o +obj-$(CONFIG_MFD_DA8XX_PRUSS) += da8xx_pru.o obj-$(CONFIG_MFD_DM355EVM_MSP) += dm355evm_msp.o obj-$(CONFIG_MFD_STMPE) += stmpe.o diff --git a/drivers/mfd/da8xx_pru.c b/drivers/mfd/da8xx_pru.c new file mode 100644 index 0000000..0fd9bb2 --- /dev/null +++ b/drivers/mfd/da8xx_pru.c @@ -0,0 +1,560 @@ +/* + * Copyright (C) 2011 Texas Instruments Incorporated + * + * 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 version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, + * whether express or implied; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct da8xx_pruss { + struct device *dev; + spinlock_t lock; + struct resource *res; + struct clk *clk; + u32 clk_freq; + void __iomem *ioaddr; +}; + +u32 pruss_get_clk_freq(struct device *dev) +{ + struct da8xx_pruss *pruss = dev_get_drvdata(dev->parent); + + return pruss->clk_freq; +} +EXPORT_SYMBOL(pruss_get_clk_freq); + +s32 pruss_disable(struct device *dev, u8 pruss_num) +{ + struct da8xx_pruss *pruss = dev_get_drvdata(dev->parent); + struct da8xx_prusscore_regs *h_pruss; + struct pruss_map *pruss_mmap = (struct pruss_map *)pruss->ioaddr; + u32 temp_reg; + u32 delay_cnt; + + if ((pruss_num != DA8XX_PRUCORE_0) && (pruss_num != DA8XX_PRUCORE_1)) + return -EINVAL; + + spin_lock(&pruss->lock); + if (pruss_num == DA8XX_PRUCORE_0) { + /* pruss deinit */ + __raw_writel(0xFFFFFFFF, (PRUSS_INTC_STATCLRINT0 & 0xFFFF)); + /* Disable PRU0 */ + h_pruss = (struct da8xx_prusscore_regs *) + &pruss_mmap->core[DA8XX_PRUCORE_0]; + + temp_reg = __raw_readl(&h_pruss->CONTROL); + temp_reg = (temp_reg & + ~DA8XX_PRUCORE_CONTROL_COUNTENABLE_MASK) | + ((DA8XX_PRUCORE_CONTROL_COUNTENABLE_DISABLE << + DA8XX_PRUCORE_CONTROL_COUNTENABLE_SHIFT) & + DA8XX_PRUCORE_CONTROL_COUNTENABLE_MASK); + __raw_writel(temp_reg, &h_pruss->CONTROL); + + for (delay_cnt = 0x10000; delay_cnt > 0; delay_cnt--) { + + temp_reg = __raw_readl(&h_pruss->CONTROL); + temp_reg = (temp_reg & + ~DA8XX_PRUCORE_CONTROL_ENABLE_MASK) | + ((DA8XX_PRUCORE_CONTROL_ENABLE_DISABLE << + DA8XX_PRUCORE_CONTROL_ENABLE_SHIFT) & + DA8XX_PRUCORE_CONTROL_ENABLE_MASK); + __raw_writel(temp_reg, &h_pruss->CONTROL); + } + + /* Reset PRU0 */ + for (delay_cnt = 0x10000; delay_cnt > 0; delay_cnt--) + __raw_writel(DA8XX_PRUCORE_CONTROL_RESETVAL, + &h_pruss->CONTROL); + + } else if (pruss_num == DA8XX_PRUCORE_1) { + /* pruss deinit */ + __raw_writel(0xFFFFFFFF, (PRUSS_INTC_STATCLRINT1 & 0xFFFF)); + /* Disable PRU1 */ + h_pruss = (struct da8xx_prusscore_regs *) + &pruss_mmap->core[DA8XX_PRUCORE_1]; + temp_reg = __raw_readl(&h_pruss->CONTROL); + temp_reg = (temp_reg & + ~DA8XX_PRUCORE_CONTROL_COUNTENABLE_MASK) | + ((DA8XX_PRUCORE_CONTROL_COUNTENABLE_DISABLE << + DA8XX_PRUCORE_CONTROL_COUNTENABLE_SHIFT) & + DA8XX_PRUCORE_CONTROL_COUNTENABLE_MASK); + __raw_writel(temp_reg, &h_pruss->CONTROL); + + for (delay_cnt = 0x10000; delay_cnt > 0; delay_cnt--) { + + temp_reg = __raw_readl(&h_pruss->CONTROL); + temp_reg = (temp_reg & + ~DA8XX_PRUCORE_CONTROL_ENABLE_MASK) | + ((DA8XX_PRUCORE_CONTROL_ENABLE_DISABLE << + DA8XX_PRUCORE_CONTROL_ENABLE_SHIFT) & + DA8XX_PRUCORE_CONTROL_ENABLE_MASK); + __raw_writel(temp_reg, &h_pruss->CONTROL); + } + + /* Reset PRU1 */ + for (delay_cnt = 0x10000; delay_cnt > 0; delay_cnt--) + __raw_writel(DA8XX_PRUCORE_CONTROL_RESETVAL, + &h_pruss->CONTROL); + } + spin_unlock(&pruss->lock); + + return 0; +} +EXPORT_SYMBOL(pruss_disable); + +s32 pruss_enable(struct device *dev, u8 pruss_num) +{ + struct da8xx_pruss *pruss = dev_get_drvdata(dev->parent); + struct da8xx_prusscore_regs *h_pruss; + struct pruss_map *pruss_mmap = (struct pruss_map *)pruss->ioaddr; + + if ((pruss_num != DA8XX_PRUCORE_0) && (pruss_num != DA8XX_PRUCORE_1)) + return -EINVAL; + + spin_lock(&pruss->lock); + if (pruss_num == DA8XX_PRUCORE_0) { + /* Reset PRU0 */ + h_pruss = (struct da8xx_prusscore_regs *) + &pruss_mmap->core[DA8XX_PRUCORE_0]; + __raw_writel(DA8XX_PRUCORE_CONTROL_RESETVAL, + &h_pruss->CONTROL); + } else if (pruss_num == DA8XX_PRUCORE_1) { + /* Reset PRU1 */ + h_pruss = (struct da8xx_prusscore_regs *) + &pruss_mmap->core[DA8XX_PRUCORE_1]; + __raw_writel(DA8XX_PRUCORE_CONTROL_RESETVAL, + &h_pruss->CONTROL); + } + spin_unlock(&pruss->lock); + + return 0; +} +EXPORT_SYMBOL(pruss_enable); + +/* Load the specified PRU with code */ +s32 pruss_load(struct device *dev, u8 pruss_num, + u32 *pruss_code, u32 code_size_in_words) +{ + struct da8xx_pruss *pruss = dev_get_drvdata(dev->parent); + struct pruss_map *pruss_mmap = (struct pruss_map *)pruss->ioaddr; + u32 *pruss_iram; + u32 i; + + if (pruss_num == DA8XX_PRUCORE_0) + pruss_iram = (u32 *)&pruss_mmap->iram0; + else if (pruss_num == DA8XX_PRUCORE_1) + pruss_iram = (u32 *)&pruss_mmap->iram1; + else + return -EINVAL; + + pruss_enable(dev, pruss_num); + + spin_lock(&pruss->lock); + /* Copy dMAX code to its instruction RAM */ + for (i = 0; i < code_size_in_words; i++) + __raw_writel(pruss_code[i], (pruss_iram + i)); + + spin_unlock(&pruss->lock); + + return 0; +} +EXPORT_SYMBOL(pruss_load); + +s32 pruss_run(struct device *dev, u8 pruss_num) +{ + struct da8xx_pruss *pruss = dev_get_drvdata(dev->parent); + struct da8xx_prusscore_regs *h_pruss; + struct pruss_map *pruss_mmap = (struct pruss_map *)pruss->ioaddr; + u32 temp_reg; + + if (pruss_num == DA8XX_PRUCORE_0) { + /* DA8XX_PRUCORE_0_REGS; */ + h_pruss = (struct da8xx_prusscore_regs *) + &pruss_mmap->core[DA8XX_PRUCORE_0]; + } else if (pruss_num == DA8XX_PRUCORE_1) { + /* DA8XX_PRUCORE_1_REGS; */ + h_pruss = (struct da8xx_prusscore_regs *) + &pruss_mmap->core[DA8XX_PRUCORE_1]; + } else + return -EINVAL; + + /* Enable dMAX, let it execute the code we just copied */ + spin_lock(&pruss->lock); + temp_reg = __raw_readl(&h_pruss->CONTROL); + temp_reg = (temp_reg & + ~DA8XX_PRUCORE_CONTROL_COUNTENABLE_MASK) | + ((DA8XX_PRUCORE_CONTROL_COUNTENABLE_ENABLE << + DA8XX_PRUCORE_CONTROL_COUNTENABLE_SHIFT) & + DA8XX_PRUCORE_CONTROL_COUNTENABLE_MASK); + __raw_writel(temp_reg, &h_pruss->CONTROL); + + temp_reg = __raw_readl(&h_pruss->CONTROL); + temp_reg = (temp_reg & + ~DA8XX_PRUCORE_CONTROL_ENABLE_MASK) | + ((DA8XX_PRUCORE_CONTROL_ENABLE_ENABLE << + DA8XX_PRUCORE_CONTROL_ENABLE_SHIFT) & + DA8XX_PRUCORE_CONTROL_ENABLE_MASK); + __raw_writel(temp_reg, &h_pruss->CONTROL); + spin_unlock(&pruss->lock); + + return 0; +} +EXPORT_SYMBOL(pruss_run); + +s32 pruss_wait_for_halt(struct device *dev, u8 pruss_num, u32 timeout) +{ + struct da8xx_pruss *pruss = dev_get_drvdata(dev->parent); + struct da8xx_prusscore_regs *h_pruss; + struct pruss_map *pruss_mmap = (struct pruss_map *)pruss->ioaddr; + u32 temp_reg; + u32 cnt = timeout; + + if (pruss_num == DA8XX_PRUCORE_0) { + /* DA8XX_PRUCORE_0_REGS; */ + h_pruss = (struct da8xx_prusscore_regs *) + &pruss_mmap->core[DA8XX_PRUCORE_0]; + } else if (pruss_num == DA8XX_PRUCORE_1) { + /* DA8XX_PRUCORE_1_REGS; */ + h_pruss = (struct da8xx_prusscore_regs *) + &pruss_mmap->core[DA8XX_PRUCORE_1]; + } else + return -EINVAL; + + while (cnt--) { + temp_reg = __raw_readl(&h_pruss->CONTROL); + if (((temp_reg & DA8XX_PRUCORE_CONTROL_RUNSTATE_MASK) >> + DA8XX_PRUCORE_CONTROL_RUNSTATE_SHIFT) == + DA8XX_PRUCORE_CONTROL_RUNSTATE_HALT) + break; + } + if (cnt == 0) + return -EBUSY; + + return 0; +} +EXPORT_SYMBOL(pruss_wait_for_halt); + +s32 pruss_writeb(struct device *dev, u32 offset, + u8 *pdatatowrite, u16 bytestowrite) +{ + struct da8xx_pruss *pruss = dev_get_drvdata(dev->parent); + u8 *paddresstowrite; + u16 loop; + offset = (u32)pruss->ioaddr + offset; + paddresstowrite = (u8 *) (offset); + + for (loop = 0; loop < bytestowrite; loop++) + __raw_writeb(*pdatatowrite++, paddresstowrite++); + + return 0; +} +EXPORT_SYMBOL(pruss_writeb); + +s32 pruss_rmwb(struct device *dev, u32 offset, u8 mask, u8 val) +{ + struct da8xx_pruss *pruss = dev_get_drvdata(dev->parent); + u32 *paddress; + u32 preg_data; + + paddress = (u32 *)((u32)pruss->ioaddr + offset); + + spin_lock(&pruss->lock); + preg_data = __raw_readb(paddress); + preg_data &= ~mask; + preg_data |= val; + __raw_writeb(preg_data, paddress); + spin_unlock(&pruss->lock); + + return 0; +} +EXPORT_SYMBOL(pruss_rmwb); + +s32 pruss_readb(struct device *dev, u32 offset, + u8 *pdatatoread, u16 bytestoread) +{ + struct da8xx_pruss *pruss = dev_get_drvdata(dev->parent); + u8 *paddresstoread; + u16 loop; + offset = (u32)pruss->ioaddr + offset; + paddresstoread = (u8 *) (offset); + + for (loop = 0; loop < bytestoread; loop++) + *pdatatoread++ = __raw_readb(paddresstoread++); + + return 0; +} +EXPORT_SYMBOL(pruss_readb); + +s32 pruss_writel(struct device *dev, u32 offset, + u32 *pdatatowrite, s16 wordstowrite) +{ + struct da8xx_pruss *pruss = dev_get_drvdata(dev->parent); + u32 *paddresstowrite; + s16 loop; + + offset = (u32)pruss->ioaddr + offset; + paddresstowrite = (u32 *)(offset); + + for (loop = 0; loop < wordstowrite; loop++) + __raw_writel(*pdatatowrite++, paddresstowrite++); + + return 0; +} +EXPORT_SYMBOL(pruss_writel); + +s32 pruss_rmwl(struct device *dev, u32 offset, u32 mask, u32 val) +{ + struct da8xx_pruss *pruss = dev_get_drvdata(dev->parent); + u32 *paddress; + u32 preg_data; + + paddress = (u32 *)((u32)pruss->ioaddr + offset); + + spin_lock(&pruss->lock); + preg_data = __raw_readl(paddress); + preg_data &= ~mask; + preg_data |= val; + __raw_writel(preg_data, paddress); + spin_unlock(&pruss->lock); + + return 0; +} +EXPORT_SYMBOL(pruss_rmwl); + +s32 pruss_readl(struct device *dev, u32 offset, + u32 *pdatatoread, s16 wordstoread) +{ + struct da8xx_pruss *pruss = dev_get_drvdata(dev->parent); + u32 *paddresstoread; + s16 loop; + + offset = (u32)pruss->ioaddr + offset; + paddresstoread = (u32 *)(offset); + + for (loop = 0; loop < wordstoread; loop++) + *pdatatoread++ = __raw_readl(paddresstoread++); + + return 0; +} +EXPORT_SYMBOL(pruss_readl); + +s32 pruss_writew(struct device *dev, u32 offset, + u16 *pdatatowrite, s16 wordstowrite) +{ + struct da8xx_pruss *pruss = dev_get_drvdata(dev->parent); + u32 *paddresstowrite; + s16 loop; + + offset = (u32)pruss->ioaddr + offset; + paddresstowrite = (u32 *)(offset); + + for (loop = 0; loop < wordstowrite; loop++) + __raw_writew(*(pdatatowrite++), (paddresstowrite++)); + + return 0; +} +EXPORT_SYMBOL(pruss_writew); + +s32 pruss_rmww(struct device *dev, u32 offset, u16 mask, u16 val) +{ + struct da8xx_pruss *pruss = dev_get_drvdata(dev->parent); + u32 *paddress; + u32 preg_data; + + paddress = (u32 *)((u32)pruss->ioaddr + offset); + + spin_lock(&pruss->lock); + preg_data = __raw_readw(paddress); + preg_data &= ~mask; + preg_data |= val; + __raw_writew(preg_data, paddress); + spin_unlock(&pruss->lock); + + return 0; +} +EXPORT_SYMBOL(pruss_rmww); + +s32 pruss_readw(struct device *dev, u32 offset, + u16 *pdatatoread, s16 wordstoread) +{ + struct da8xx_pruss *pruss = dev_get_drvdata(dev->parent); + u32 *paddresstoread; + s16 loop; + + offset = (u32)pruss->ioaddr + offset; + paddresstoread = (u32 *)(offset); + + for (loop = 0; loop < wordstoread; loop++) + *pdatatoread++ = __raw_readw(paddresstoread++); + + return 0; +} +EXPORT_SYMBOL(pruss_readw); + +s32 pruss_idx_writel(struct device *dev, u32 offset, u32 value) +{ + struct da8xx_pruss *pruss = dev_get_drvdata(dev->parent); + u32 *paddresstowrite; + + paddresstowrite = (u32 *)(pruss->ioaddr + offset); + __raw_writel(value, paddresstowrite); + + return 0; +} +EXPORT_SYMBOL(pruss_idx_writel); + +static int pruss_mfd_add_devices(struct platform_device *pdev) +{ + struct da8xx_pruss_devices *dev_data = pdev->dev.platform_data; + struct device *dev = &pdev->dev; + struct mfd_cell cell; + u32 err, count; + + for (count = 0; dev_data[count].dev_name != NULL; count++) { + memset(&cell, 0, sizeof(struct mfd_cell)); + cell.id = count; + cell.name = dev_data[count].dev_name; + cell.platform_data = dev_data[count].pdata; + cell.data_size = dev_data[count].pdata_size; + cell.resources = dev_data[count].resources; + cell.num_resources = dev_data[count].num_resources; + + err = mfd_add_devices(dev, 0, &cell, 1, NULL, 0); + if (err) { + dev_err(dev, "cannot add mfd cells\n"); + return err; + } + dev_info(dev, "mfd: added %s device\n", + dev_data[count].dev_name); + } + + return err; +} + +static int __devinit da8xx_pruss_probe(struct platform_device *pdev) +{ + struct da8xx_pruss *pruss_dev = NULL; + u32 err; + + pruss_dev = kzalloc(sizeof(struct da8xx_pruss), GFP_KERNEL); + if (!pruss_dev) + return -ENOMEM; + + pruss_dev->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!pruss_dev->res) { + dev_err(&pdev->dev, + "unable to get pruss memory resources!\n"); + err = -ENODEV; + goto probe_exit_kfree; + } + + if (!request_mem_region(pruss_dev->res->start, + resource_size(pruss_dev->res), dev_name(&pdev->dev))) { + dev_err(&pdev->dev, "pruss memory region already claimed!\n"); + err = -EBUSY; + goto probe_exit_kfree; + } + + pruss_dev->ioaddr = ioremap(pruss_dev->res->start, + resource_size(pruss_dev->res)); + if (!pruss_dev->ioaddr) { + dev_err(&pdev->dev, "ioremap failed\n"); + err = -ENOMEM; + goto probe_exit_free_region; + } + + pruss_dev->clk = clk_get(NULL, "pruss"); + if (IS_ERR(pruss_dev->clk)) { + dev_err(&pdev->dev, "no clock available: pruss\n"); + err = -ENODEV; + pruss_dev->clk = NULL; + goto probe_exit_iounmap; + } + spin_lock_init(&pruss_dev->lock); + + clk_enable(pruss_dev->clk); + pruss_dev->clk_freq = clk_get_rate(pruss_dev->clk); + + err = pruss_mfd_add_devices(pdev); + if (err) + goto probe_exit_clock; + + platform_set_drvdata(pdev, pruss_dev); + pruss_dev->dev = &pdev->dev; + return 0; + +probe_exit_clock: + clk_put(pruss_dev->clk); + clk_disable(pruss_dev->clk); +probe_exit_iounmap: + iounmap(pruss_dev->ioaddr); +probe_exit_free_region: + release_mem_region(pruss_dev->res->start, + resource_size(pruss_dev->res)); +probe_exit_kfree: + kfree(pruss_dev); + return err; +} + +static int __devexit da8xx_pruss_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct da8xx_pruss *pruss = dev_get_drvdata(dev); + + mfd_remove_devices(dev); + pruss_disable(dev, DA8XX_PRUCORE_0); + pruss_disable(dev, DA8XX_PRUCORE_1); + clk_disable(pruss->clk); + clk_put(pruss->clk); + iounmap(pruss->ioaddr); + release_mem_region(pruss->res->start, resource_size(pruss->res)); + kfree(pruss); + dev_set_drvdata(dev, NULL); + return 0; +} + +static struct platform_driver da8xx_pruss_driver = { + .probe = da8xx_pruss_probe, + .remove = __devexit_p(da8xx_pruss_remove), + .driver = { + .name = "pruss_mfd", + .owner = THIS_MODULE, + } +}; + +static int __init da8xx_pruss_init(void) +{ + return platform_driver_register(&da8xx_pruss_driver); +} +module_init(da8xx_pruss_init); + +static void __exit da8xx_pruss_exit(void) +{ + platform_driver_unregister(&da8xx_pruss_driver); +} +module_exit(da8xx_pruss_exit); + +MODULE_DESCRIPTION("Programmable Realtime Unit (PRU) Driver"); +MODULE_AUTHOR("Subhasish Ghosh"); +MODULE_LICENSE("GPL"); diff --git a/include/linux/mfd/da8xx/da8xx_pru.h b/include/linux/mfd/da8xx/da8xx_pru.h new file mode 100644 index 0000000..ba65ec0 --- /dev/null +++ b/include/linux/mfd/da8xx/da8xx_pru.h @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2010 Texas Instruments Incorporated + * Author: Jitendra Kumar + * + * 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 version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, + * whether express or implied; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#ifndef _PRUSS_H_ +#define _PRUSS_H_ + +#include +#include +#include "da8xx_prucore.h" + +#define PRUSS_NUM0 DA8XX_PRUCORE_0 +#define PRUSS_NUM1 DA8XX_PRUCORE_1 + +#define PRUSS_PRU0_BASE_ADDRESS 0 +#define PRUSS_INTC_BASE_ADDRESS (PRUSS_PRU0_BASE_ADDRESS + 0x4000) +#define PRUSS_INTC_GLBLEN (PRUSS_INTC_BASE_ADDRESS + 0x10) +#define PRUSS_INTC_GLBLNSTLVL (PRUSS_INTC_BASE_ADDRESS + 0x1C) +#define PRUSS_INTC_STATIDXSET (PRUSS_INTC_BASE_ADDRESS + 0x20) +#define PRUSS_INTC_STATIDXCLR (PRUSS_INTC_BASE_ADDRESS + 0x24) +#define PRUSS_INTC_ENIDXSET (PRUSS_INTC_BASE_ADDRESS + 0x28) +#define PRUSS_INTC_ENIDXCLR (PRUSS_INTC_BASE_ADDRESS + 0x2C) +#define PRUSS_INTC_HSTINTENIDXSET (PRUSS_INTC_BASE_ADDRESS + 0x34) +#define PRUSS_INTC_HSTINTENIDXCLR (PRUSS_INTC_BASE_ADDRESS + 0x38) +#define PRUSS_INTC_GLBLPRIIDX (PRUSS_INTC_BASE_ADDRESS + 0x80) +#define PRUSS_INTC_STATSETINT0 (PRUSS_INTC_BASE_ADDRESS + 0x200) +#define PRUSS_INTC_STATSETINT1 (PRUSS_INTC_BASE_ADDRESS + 0x204) +#define PRUSS_INTC_STATCLRINT0 (PRUSS_INTC_BASE_ADDRESS + 0x280) +#define PRUSS_INTC_STATCLRINT1 (PRUSS_INTC_BASE_ADDRESS + 0x284) +#define PRUSS_INTC_ENABLESET0 (PRUSS_INTC_BASE_ADDRESS + 0x300) +#define PRUSS_INTC_ENABLESET1 (PRUSS_INTC_BASE_ADDRESS + 0x304) +#define PRUSS_INTC_ENABLECLR0 (PRUSS_INTC_BASE_ADDRESS + 0x380) +#define PRUSS_INTC_ENABLECLR1 (PRUSS_INTC_BASE_ADDRESS + 0x384) +#define PRUSS_INTC_CHANMAP0 (PRUSS_INTC_BASE_ADDRESS + 0x400) +#define PRUSS_INTC_CHANMAP1 (PRUSS_INTC_BASE_ADDRESS + 0x404) +#define PRUSS_INTC_CHANMAP2 (PRUSS_INTC_BASE_ADDRESS + 0x408) +#define PRUSS_INTC_CHANMAP3 (PRUSS_INTC_BASE_ADDRESS + 0x40C) +#define PRUSS_INTC_CHANMAP4 (PRUSS_INTC_BASE_ADDRESS + 0x410) +#define PRUSS_INTC_CHANMAP5 (PRUSS_INTC_BASE_ADDRESS + 0x414) +#define PRUSS_INTC_CHANMAP6 (PRUSS_INTC_BASE_ADDRESS + 0x418) +#define PRUSS_INTC_CHANMAP7 (PRUSS_INTC_BASE_ADDRESS + 0x41C) +#define PRUSS_INTC_CHANMAP8 (PRUSS_INTC_BASE_ADDRESS + 0x420) +#define PRUSS_INTC_CHANMAP9 (PRUSS_INTC_BASE_ADDRESS + 0x424) +#define PRUSS_INTC_CHANMAP10 (PRUSS_INTC_BASE_ADDRESS + 0x428) +#define PRUSS_INTC_CHANMAP11 (PRUSS_INTC_BASE_ADDRESS + 0x42C) +#define PRUSS_INTC_CHANMAP12 (PRUSS_INTC_BASE_ADDRESS + 0x430) +#define PRUSS_INTC_CHANMAP13 (PRUSS_INTC_BASE_ADDRESS + 0x434) +#define PRUSS_INTC_CHANMAP14 (PRUSS_INTC_BASE_ADDRESS + 0x438) +#define PRUSS_INTC_CHANMAP15 (PRUSS_INTC_BASE_ADDRESS + 0x43C) +#define PRUSS_INTC_HOSTMAP0 (PRUSS_INTC_BASE_ADDRESS + 0x800) +#define PRUSS_INTC_HOSTMAP1 (PRUSS_INTC_BASE_ADDRESS + 0x804) +#define PRUSS_INTC_HOSTMAP2 (PRUSS_INTC_BASE_ADDRESS + 0x808) +#define PRUSS_INTC_POLARITY0 (PRUSS_INTC_BASE_ADDRESS + 0xD00) +#define PRUSS_INTC_POLARITY1 (PRUSS_INTC_BASE_ADDRESS + 0xD04) +#define PRUSS_INTC_TYPE0 (PRUSS_INTC_BASE_ADDRESS + 0xD80) +#define PRUSS_INTC_TYPE1 (PRUSS_INTC_BASE_ADDRESS + 0xD84) +#define PRUSS_INTC_HOSTINTEN (PRUSS_INTC_BASE_ADDRESS + 0x1500) +#define PRUSS_INTC_HOSTINTLVL_MAX 9 + +#define PRU_INTC_HOSTMAP0_CHAN (0x03020100) +#define PRU_INTC_HOSTMAP1_CHAN (0x07060504) +#define PRU_INTC_HOSTMAP2_CHAN (0x00000908) + +#define PRU_INTC_CHANMAP7_SYS_EVT31 (0x00000000) +#define PRU_INTC_CHANMAP8_FULL (0x02020100) +#define PRU_INTC_CHANMAP9_FULL (0x04040303) +#define PRU_INTC_CHANMAP10_FULL (0x06060505) +#define PRU_INTC_CHANMAP11_FULL (0x08080707) +#define PRU_INTC_CHANMAP12_FULL (0x00010909) +#define PRU_INTC_CHANMAP8_HALF (0x03020100) +#define PRU_INTC_CHANMAP9_HALF (0x07060504) +#define PRU_INTC_CHANMAP10_HALF (0x03020908) +#define PRU_INTC_CHANMAP11_HALF (0x07060504) +#define PRU_INTC_CHANMAP12_HALF (0x00010908) + +#define PRU_INTC_REGMAP_MASK (0xFFFFFFFF) + +struct da8xx_pruss_devices { + const char *dev_name; + void *pdata; + size_t pdata_size; + int (*setup)(void); + u32 num_resources; + struct resource *resources; +}; + +u32 pruss_get_clk_freq(struct device *dev); + +s32 pruss_enable(struct device *dev, u8 pruss_num); + +s32 pruss_load(struct device *dev, u8 pruss_num, + u32 *pruss_code, u32 code_size_in_words); + +s32 pruss_run(struct device *dev, u8 pruss_num); + +s32 pruss_wait_for_halt(struct device *dev, u8 pruss_num, u32 timeout); + +s32 pruss_disable(struct device *dev, u8 pruss_num); + +s32 pruss_writeb(struct device *dev, u32 offset, + u8 *pdatatowrite, u16 wordstowrite); + +s32 pruss_rmwb(struct device *dev, u32 offset, u8 mask, u8 val); + +s32 pruss_readb(struct device *dev, u32 offset, + u8 *pdatatoread, u16 wordstoread); + +s32 pruss_readl(struct device *dev, u32 offset, + u32 *pdatatoread, s16 wordstoread); + +s32 pruss_writel(struct device *dev, u32 offset, + u32 *pdatatoread, s16 wordstoread); + +s32 pruss_rmwl(struct device *dev, u32 offset, u32 mask, u32 val); + +s32 pruss_idx_writel(struct device *dev, u32 offset, u32 value); + +s32 pruss_writew(struct device *dev, u32 offset, + u16 *datatowrite, s16 wordstowrite); + +s32 pruss_rmww(struct device *dev, u32 offset, u16 mask, u16 val); + +s32 pruss_readw(struct device *dev, u32 offset, + u16 *pdatatoread, s16 wordstoread); +#endif /* End _PRUSS_H_ */ diff --git a/include/linux/mfd/da8xx/da8xx_prucore.h b/include/linux/mfd/da8xx/da8xx_prucore.h new file mode 100644 index 0000000..913d56f --- /dev/null +++ b/include/linux/mfd/da8xx/da8xx_prucore.h @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2010 Texas Instruments Incorporated + * Author: Jitendra Kumar + * + * 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 version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, + * whether express or implied; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#ifndef _DA8XX_PRUCORE_H_ +#define _DA8XX_PRUCORE_H_ + +#include + +#define DA8XX_PRUCORE_0 (0) +#define DA8XX_PRUCORE_1 (1) + +#define DA8XX_PRUCORE_CONTROL_PCRESETVAL_MASK (0xFFFF0000u) +#define DA8XX_PRUCORE_CONTROL_PCRESETVAL_SHIFT (0x00000010u) +#define DA8XX_PRUCORE_CONTROL_PCRESETVAL_RESETVAL (0x00000000u) +#define DA8XX_PRUCORE_CONTROL_RUNSTATE_MASK (0x00008000u) +#define DA8XX_PRUCORE_CONTROL_RUNSTATE_SHIFT (0x0000000Fu) +#define DA8XX_PRUCORE_CONTROL_RUNSTATE_RESETVAL (0x00000000u) +#define DA8XX_PRUCORE_CONTROL_RUNSTATE_HALT (0x00000000u) +#define DA8XX_PRUCORE_CONTROL_RUNSTATE_RUN (0x00000001u) +#define DA8XX_PRUCORE_CONTROL_SINGLESTEP_MASK (0x00000100u) +#define DA8XX_PRUCORE_CONTROL_SINGLESTEP_SHIFT (0x00000008u) +#define DA8XX_PRUCORE_CONTROL_SINGLESTEP_RESETVAL (0x00000000u) +#define DA8XX_PRUCORE_CONTROL_SINGLESTEP_FREERUN (0x00000000u) +#define DA8XX_PRUCORE_CONTROL_SINGLESTEP_SINGLE (0x00000001u) +#define DA8XX_PRUCORE_CONTROL_COUNTENABLE_MASK (0x00000008u) +#define DA8XX_PRUCORE_CONTROL_COUNTENABLE_SHIFT (0x00000003u) +#define DA8XX_PRUCORE_CONTROL_COUNTENABLE_RESETVAL (0x00000000u) +#define DA8XX_PRUCORE_CONTROL_COUNTENABLE_DISABLE (0x00000000u) +#define DA8XX_PRUCORE_CONTROL_COUNTENABLE_ENABLE (0x00000001u) +#define DA8XX_PRUCORE_CONTROL_SLEEPING_MASK (0x00000004u) +#define DA8XX_PRUCORE_CONTROL_SLEEPING_SHIFT (0x00000002u) +#define DA8XX_PRUCORE_CONTROL_SLEEPING_RESETVAL (0x00000000u) +#define DA8XX_PRUCORE_CONTROL_SLEEPING_NOTASLEEP (0x00000000u) +#define DA8XX_PRUCORE_CONTROL_SLEEPING_ASLEEP (0x00000001u) +#define DA8XX_PRUCORE_CONTROL_ENABLE_MASK (0x00000002u) +#define DA8XX_PRUCORE_CONTROL_ENABLE_SHIFT (0x00000001u) +#define DA8XX_PRUCORE_CONTROL_ENABLE_RESETVAL (0x00000000u) +#define DA8XX_PRUCORE_CONTROL_ENABLE_DISABLE (0x00000000u) +#define DA8XX_PRUCORE_CONTROL_ENABLE_ENABLE (0x00000001u) +#define DA8XX_PRUCORE_CONTROL_SOFTRESET_MASK (0x00000001u) +#define DA8XX_PRUCORE_CONTROL_SOFTRESET_SHIFT (0x00000000u) +#define DA8XX_PRUCORE_CONTROL_SOFTRESET_RESETVAL (0x00000000u) +#define DA8XX_PRUCORE_CONTROL_SOFTRESET_RESET (0x00000000u) +#define DA8XX_PRUCORE_CONTROL_SOFTRESET_OUT_OF_RESET (0x00000001u) +#define DA8XX_PRUCORE_CONTROL_RESETVAL (0x00000000u) + +struct da8xx_prusscore_regs { + u32 CONTROL; + u32 STATUS; + u32 WAKEUP; + u32 CYCLECNT; + u32 STALLCNT; + u8 RSVD0[12]; + u32 CONTABBLKIDX0; + u32 CONTABBLKIDX1; + u32 CONTABPROPTR0; + u32 CONTABPROPTR1; + u8 RSVD1[976]; + u32 INTGPR[32]; + u32 INTCTER[32]; + u8 RSVD2[768]; +}; + +struct pruss_intc_regs { + u32 REVID; + u32 CONTROL; + u8 RES1[8]; + u32 GLBLEN; + u8 RES2[8]; + u32 GLBLNSTLVL; + u32 STATIDXSET; + u32 STATIDXCLR; + u32 ENIDXSET; + u32 ENIDXCLR; + u8 RES3[4]; + u32 HOSTINTENIDXSET; + u32 HOSTINTENIDXCLR; + u8 RES4[68]; + u32 GLBLPRIIDX; + u8 RES5[380]; + u32 STATSETINT[2]; + u8 RES6[120]; + u32 STATCLRINT[2]; + u8 RES7[120]; + u32 ENABLESET[2]; + u8 RES8[120]; + u32 ENABLECLR[2]; + u8 RES9[120]; + u32 CHANMAP[16]; + u8 RES10[960]; + u32 HOSTMAP[2]; + u8 RES11[248]; + u32 HOSTINTPRIIDX[10]; + u8 RES12[984]; + u32 POLARITY[2]; + u8 RES13[120]; + u32 TYPE[2]; + u8 RES14[888]; + u32 HOSTINTNSTLVL[10]; + u8 RES15[984]; + u32 HOSTINTEN; + u8 RES16[6907]; +}; + +struct pruss_map { + u8 dram0[512]; + u8 res1[7680]; + u8 dram1[512]; + u8 res2[7680]; + struct pruss_intc_regs intc; + struct da8xx_prusscore_regs core[2]; + u8 iram0[4096]; + u8 res3[12288]; + u8 iram1[4096]; + u8 res4[12288]; +}; + +#endif