| 
									
										
										
										
											2011-02-12 18:22:49 -08:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Copyright (C) 2011 Google, Inc. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Author: | 
					
						
							|  |  |  |  *	Colin Cross <ccross@android.com> | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This software is licensed under the terms of the GNU General Public | 
					
						
							|  |  |  |  * License version 2, as published by the Free Software Foundation, and | 
					
						
							|  |  |  |  * may be copied, distributed, and modified under those terms. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is distributed in the hope that it will be useful, | 
					
						
							|  |  |  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
					
						
							|  |  |  |  * GNU General Public License for more details. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <linux/kernel.h>
 | 
					
						
							| 
									
										
										
										
											2011-10-16 16:54:51 -07:00
										 |  |  | #include <linux/device.h>
 | 
					
						
							| 
									
										
										
										
											2011-02-12 18:22:49 -08:00
										 |  |  | #include <linux/clk.h>
 | 
					
						
							|  |  |  | #include <linux/err.h>
 | 
					
						
							|  |  |  | #include <linux/io.h>
 | 
					
						
							|  |  |  | #include <linux/module.h>
 | 
					
						
							| 
									
										
										
										
											2011-10-17 16:05:22 -07:00
										 |  |  | #include <linux/of.h>
 | 
					
						
							| 
									
										
										
										
											2011-10-16 16:54:51 -07:00
										 |  |  | #include <linux/platform_device.h>
 | 
					
						
							|  |  |  | #include <linux/platform_data/tegra_emc.h>
 | 
					
						
							| 
									
										
										
										
											2011-02-12 18:22:49 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include "tegra2_emc.h"
 | 
					
						
							| 
									
										
										
										
											2011-10-17 16:05:22 -07:00
										 |  |  | #include "fuse.h"
 | 
					
						
							| 
									
										
										
										
											2011-02-12 18:22:49 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | #ifdef CONFIG_TEGRA_EMC_SCALING_ENABLE
 | 
					
						
							|  |  |  | static bool emc_enable = true; | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | static bool emc_enable; | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | module_param(emc_enable, bool, 0644); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-16 16:54:51 -07:00
										 |  |  | static struct platform_device *emc_pdev; | 
					
						
							|  |  |  | static void __iomem *emc_regbase; | 
					
						
							| 
									
										
										
										
											2011-02-12 18:22:49 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | static inline void emc_writel(u32 val, unsigned long addr) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2011-10-16 16:54:51 -07:00
										 |  |  | 	writel(val, emc_regbase + addr); | 
					
						
							| 
									
										
										
										
											2011-02-12 18:22:49 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline u32 emc_readl(unsigned long addr) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2011-10-16 16:54:51 -07:00
										 |  |  | 	return readl(emc_regbase + addr); | 
					
						
							| 
									
										
										
										
											2011-02-12 18:22:49 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const unsigned long emc_reg_addr[TEGRA_EMC_NUM_REGS] = { | 
					
						
							|  |  |  | 	0x2c,	/* RC */ | 
					
						
							|  |  |  | 	0x30,	/* RFC */ | 
					
						
							|  |  |  | 	0x34,	/* RAS */ | 
					
						
							|  |  |  | 	0x38,	/* RP */ | 
					
						
							|  |  |  | 	0x3c,	/* R2W */ | 
					
						
							|  |  |  | 	0x40,	/* W2R */ | 
					
						
							|  |  |  | 	0x44,	/* R2P */ | 
					
						
							|  |  |  | 	0x48,	/* W2P */ | 
					
						
							|  |  |  | 	0x4c,	/* RD_RCD */ | 
					
						
							|  |  |  | 	0x50,	/* WR_RCD */ | 
					
						
							|  |  |  | 	0x54,	/* RRD */ | 
					
						
							|  |  |  | 	0x58,	/* REXT */ | 
					
						
							|  |  |  | 	0x5c,	/* WDV */ | 
					
						
							|  |  |  | 	0x60,	/* QUSE */ | 
					
						
							|  |  |  | 	0x64,	/* QRST */ | 
					
						
							|  |  |  | 	0x68,	/* QSAFE */ | 
					
						
							|  |  |  | 	0x6c,	/* RDV */ | 
					
						
							|  |  |  | 	0x70,	/* REFRESH */ | 
					
						
							|  |  |  | 	0x74,	/* BURST_REFRESH_NUM */ | 
					
						
							|  |  |  | 	0x78,	/* PDEX2WR */ | 
					
						
							|  |  |  | 	0x7c,	/* PDEX2RD */ | 
					
						
							|  |  |  | 	0x80,	/* PCHG2PDEN */ | 
					
						
							|  |  |  | 	0x84,	/* ACT2PDEN */ | 
					
						
							|  |  |  | 	0x88,	/* AR2PDEN */ | 
					
						
							|  |  |  | 	0x8c,	/* RW2PDEN */ | 
					
						
							|  |  |  | 	0x90,	/* TXSR */ | 
					
						
							|  |  |  | 	0x94,	/* TCKE */ | 
					
						
							|  |  |  | 	0x98,	/* TFAW */ | 
					
						
							|  |  |  | 	0x9c,	/* TRPAB */ | 
					
						
							|  |  |  | 	0xa0,	/* TCLKSTABLE */ | 
					
						
							|  |  |  | 	0xa4,	/* TCLKSTOP */ | 
					
						
							|  |  |  | 	0xa8,	/* TREFBW */ | 
					
						
							|  |  |  | 	0xac,	/* QUSE_EXTRA */ | 
					
						
							|  |  |  | 	0x114,	/* FBIO_CFG6 */ | 
					
						
							|  |  |  | 	0xb0,	/* ODT_WRITE */ | 
					
						
							|  |  |  | 	0xb4,	/* ODT_READ */ | 
					
						
							|  |  |  | 	0x104,	/* FBIO_CFG5 */ | 
					
						
							|  |  |  | 	0x2bc,	/* CFG_DIG_DLL */ | 
					
						
							|  |  |  | 	0x2c0,	/* DLL_XFORM_DQS */ | 
					
						
							|  |  |  | 	0x2c4,	/* DLL_XFORM_QUSE */ | 
					
						
							|  |  |  | 	0x2e0,	/* ZCAL_REF_CNT */ | 
					
						
							|  |  |  | 	0x2e4,	/* ZCAL_WAIT_CNT */ | 
					
						
							|  |  |  | 	0x2a8,	/* AUTO_CAL_INTERVAL */ | 
					
						
							|  |  |  | 	0x2d0,	/* CFG_CLKTRIM_0 */ | 
					
						
							|  |  |  | 	0x2d4,	/* CFG_CLKTRIM_1 */ | 
					
						
							|  |  |  | 	0x2d8,	/* CFG_CLKTRIM_2 */ | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Select the closest EMC rate that is higher than the requested rate */ | 
					
						
							|  |  |  | long tegra_emc_round_rate(unsigned long rate) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2011-10-16 16:54:51 -07:00
										 |  |  | 	struct tegra_emc_pdata *pdata; | 
					
						
							| 
									
										
										
										
											2011-02-12 18:22:49 -08:00
										 |  |  | 	int i; | 
					
						
							|  |  |  | 	int best = -1; | 
					
						
							|  |  |  | 	unsigned long distance = ULONG_MAX; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-16 16:54:51 -07:00
										 |  |  | 	if (!emc_pdev) | 
					
						
							| 
									
										
										
										
											2011-02-12 18:22:49 -08:00
										 |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-16 16:54:51 -07:00
										 |  |  | 	pdata = emc_pdev->dev.platform_data; | 
					
						
							| 
									
										
										
										
											2011-02-12 18:22:49 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	pr_debug("%s: %lu\n", __func__, rate); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * The EMC clock rate is twice the bus rate, and the bus rate is | 
					
						
							|  |  |  | 	 * measured in kHz | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	rate = rate / 2 / 1000; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-16 16:54:51 -07:00
										 |  |  | 	for (i = 0; i < pdata->num_tables; i++) { | 
					
						
							|  |  |  | 		if (pdata->tables[i].rate >= rate && | 
					
						
							|  |  |  | 		    (pdata->tables[i].rate - rate) < distance) { | 
					
						
							|  |  |  | 			distance = pdata->tables[i].rate - rate; | 
					
						
							| 
									
										
										
										
											2011-02-12 18:22:49 -08:00
										 |  |  | 			best = i; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (best < 0) | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-16 16:54:51 -07:00
										 |  |  | 	pr_debug("%s: using %lu\n", __func__, pdata->tables[best].rate); | 
					
						
							| 
									
										
										
										
											2011-02-12 18:22:49 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-16 16:54:51 -07:00
										 |  |  | 	return pdata->tables[best].rate * 2 * 1000; | 
					
						
							| 
									
										
										
										
											2011-02-12 18:22:49 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * The EMC registers have shadow registers.  When the EMC clock is updated | 
					
						
							|  |  |  |  * in the clock controller, the shadow registers are copied to the active | 
					
						
							|  |  |  |  * registers, allowing glitchless memory bus frequency changes. | 
					
						
							|  |  |  |  * This function updates the shadow registers for a new clock frequency, | 
					
						
							|  |  |  |  * and relies on the clock lock on the emc clock to avoid races between | 
					
						
							|  |  |  |  * multiple frequency changes | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | int tegra_emc_set_rate(unsigned long rate) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2011-10-16 16:54:51 -07:00
										 |  |  | 	struct tegra_emc_pdata *pdata; | 
					
						
							| 
									
										
										
										
											2011-02-12 18:22:49 -08:00
										 |  |  | 	int i; | 
					
						
							|  |  |  | 	int j; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-16 16:54:51 -07:00
										 |  |  | 	if (!emc_pdev) | 
					
						
							| 
									
										
										
										
											2011-02-12 18:22:49 -08:00
										 |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-16 16:54:51 -07:00
										 |  |  | 	pdata = emc_pdev->dev.platform_data; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-12 18:22:49 -08:00
										 |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * The EMC clock rate is twice the bus rate, and the bus rate is | 
					
						
							|  |  |  | 	 * measured in kHz | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	rate = rate / 2 / 1000; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-16 16:54:51 -07:00
										 |  |  | 	for (i = 0; i < pdata->num_tables; i++) | 
					
						
							|  |  |  | 		if (pdata->tables[i].rate == rate) | 
					
						
							| 
									
										
										
										
											2011-02-12 18:22:49 -08:00
										 |  |  | 			break; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-16 16:54:51 -07:00
										 |  |  | 	if (i >= pdata->num_tables) | 
					
						
							| 
									
										
										
										
											2011-02-12 18:22:49 -08:00
										 |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pr_debug("%s: setting to %lu\n", __func__, rate); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (j = 0; j < TEGRA_EMC_NUM_REGS; j++) | 
					
						
							| 
									
										
										
										
											2011-10-16 16:54:51 -07:00
										 |  |  | 		emc_writel(pdata->tables[i].regs[j], emc_reg_addr[j]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	emc_readl(pdata->tables[i].regs[TEGRA_EMC_NUM_REGS - 1]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-17 16:05:22 -07:00
										 |  |  | #ifdef CONFIG_OF
 | 
					
						
							|  |  |  | static struct device_node *tegra_emc_ramcode_devnode(struct device_node *np) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct device_node *iter; | 
					
						
							|  |  |  | 	u32 reg; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for_each_child_of_node(np, iter) { | 
					
						
							| 
									
										
										
										
											2013-05-12 10:26:49 +00:00
										 |  |  | 		if (of_property_read_u32(iter, "nvidia,ram-code", ®)) | 
					
						
							| 
									
										
										
										
											2011-10-17 16:05:22 -07:00
										 |  |  | 			continue; | 
					
						
							|  |  |  | 		if (reg == tegra_bct_strapping) | 
					
						
							|  |  |  | 			return of_node_get(iter); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct tegra_emc_pdata *tegra_emc_dt_parse_pdata( | 
					
						
							|  |  |  | 		struct platform_device *pdev) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct device_node *np = pdev->dev.of_node; | 
					
						
							|  |  |  | 	struct device_node *tnp, *iter; | 
					
						
							|  |  |  | 	struct tegra_emc_pdata *pdata; | 
					
						
							|  |  |  | 	int ret, i, num_tables; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!np) | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (of_find_property(np, "nvidia,use-ram-code", NULL)) { | 
					
						
							|  |  |  | 		tnp = tegra_emc_ramcode_devnode(np); | 
					
						
							|  |  |  | 		if (!tnp) | 
					
						
							|  |  |  | 			dev_warn(&pdev->dev, | 
					
						
							|  |  |  | 				 "can't find emc table for ram-code 0x%02x\n", | 
					
						
							|  |  |  | 				 tegra_bct_strapping); | 
					
						
							|  |  |  | 	} else | 
					
						
							|  |  |  | 		tnp = of_node_get(np); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!tnp) | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	num_tables = 0; | 
					
						
							|  |  |  | 	for_each_child_of_node(tnp, iter) | 
					
						
							|  |  |  | 		if (of_device_is_compatible(iter, "nvidia,tegra20-emc-table")) | 
					
						
							|  |  |  | 			num_tables++; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!num_tables) { | 
					
						
							|  |  |  | 		pdata = NULL; | 
					
						
							|  |  |  | 		goto out; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); | 
					
						
							|  |  |  | 	pdata->tables = devm_kzalloc(&pdev->dev, | 
					
						
							|  |  |  | 				     sizeof(*pdata->tables) * num_tables, | 
					
						
							|  |  |  | 				     GFP_KERNEL); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	i = 0; | 
					
						
							|  |  |  | 	for_each_child_of_node(tnp, iter) { | 
					
						
							|  |  |  | 		u32 prop; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		ret = of_property_read_u32(iter, "clock-frequency", &prop); | 
					
						
							|  |  |  | 		if (ret) { | 
					
						
							|  |  |  | 			dev_err(&pdev->dev, "no clock-frequency in %s\n", | 
					
						
							|  |  |  | 				iter->full_name); | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		pdata->tables[i].rate = prop; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		ret = of_property_read_u32_array(iter, "nvidia,emc-registers", | 
					
						
							|  |  |  | 						 pdata->tables[i].regs, | 
					
						
							|  |  |  | 						 TEGRA_EMC_NUM_REGS); | 
					
						
							|  |  |  | 		if (ret) { | 
					
						
							|  |  |  | 			dev_err(&pdev->dev, | 
					
						
							|  |  |  | 				"malformed emc-registers property in %s\n", | 
					
						
							|  |  |  | 				iter->full_name); | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		i++; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	pdata->num_tables = i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | out: | 
					
						
							|  |  |  | 	of_node_put(tnp); | 
					
						
							|  |  |  | 	return pdata; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | static struct tegra_emc_pdata *tegra_emc_dt_parse_pdata( | 
					
						
							|  |  |  | 		struct platform_device *pdev) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-12-21 14:02:24 -08:00
										 |  |  | static struct tegra_emc_pdata *tegra_emc_fill_pdata(struct platform_device *pdev) | 
					
						
							| 
									
										
										
										
											2011-10-17 16:05:22 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct clk *c = clk_get_sys(NULL, "emc"); | 
					
						
							|  |  |  | 	struct tegra_emc_pdata *pdata; | 
					
						
							|  |  |  | 	unsigned long khz; | 
					
						
							|  |  |  | 	int i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	WARN_ON(pdev->dev.platform_data); | 
					
						
							| 
									
										
										
										
											2013-02-24 10:51:00 +00:00
										 |  |  | 	BUG_ON(IS_ERR(c)); | 
					
						
							| 
									
										
										
										
											2011-10-17 16:05:22 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); | 
					
						
							|  |  |  | 	pdata->tables = devm_kzalloc(&pdev->dev, sizeof(*pdata->tables), | 
					
						
							|  |  |  | 				     GFP_KERNEL); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-01-26 15:12:23 +00:00
										 |  |  | 	pdata->tables[0].rate = clk_get_rate(c) / 2 / 1000; | 
					
						
							| 
									
										
										
										
											2011-10-17 16:05:22 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	for (i = 0; i < TEGRA_EMC_NUM_REGS; i++) | 
					
						
							|  |  |  | 		pdata->tables[0].regs[i] = emc_readl(emc_reg_addr[i]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pdata->num_tables = 1; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-01-26 15:12:23 +00:00
										 |  |  | 	khz = pdata->tables[0].rate; | 
					
						
							| 
									
										
										
										
											2011-10-17 16:05:22 -07:00
										 |  |  | 	dev_info(&pdev->dev, "no tables provided, using %ld kHz emc, " | 
					
						
							| 
									
										
										
										
											2012-01-26 15:12:23 +00:00
										 |  |  | 		 "%ld kHz mem\n", khz * 2, khz); | 
					
						
							| 
									
										
										
										
											2011-10-17 16:05:22 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return pdata; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-12-21 14:02:24 -08:00
										 |  |  | static int tegra_emc_probe(struct platform_device *pdev) | 
					
						
							| 
									
										
										
										
											2011-10-16 16:54:51 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct tegra_emc_pdata *pdata; | 
					
						
							|  |  |  | 	struct resource *res; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!emc_enable) { | 
					
						
							|  |  |  | 		dev_err(&pdev->dev, "disabled per module parameter\n"); | 
					
						
							|  |  |  | 		return -ENODEV; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 
					
						
							| 
									
										
										
										
											2013-01-21 11:08:55 +01:00
										 |  |  | 	emc_regbase = devm_ioremap_resource(&pdev->dev, res); | 
					
						
							|  |  |  | 	if (IS_ERR(emc_regbase)) | 
					
						
							|  |  |  | 		return PTR_ERR(emc_regbase); | 
					
						
							| 
									
										
										
										
											2011-10-17 16:05:22 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	pdata = pdev->dev.platform_data; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!pdata) | 
					
						
							|  |  |  | 		pdata = tegra_emc_dt_parse_pdata(pdev); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!pdata) | 
					
						
							|  |  |  | 		pdata = tegra_emc_fill_pdata(pdev); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pdev->dev.platform_data = pdata; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-16 16:54:51 -07:00
										 |  |  | 	emc_pdev = pdev; | 
					
						
							| 
									
										
										
										
											2011-02-12 18:22:49 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-12-21 14:02:24 -08:00
										 |  |  | static struct of_device_id tegra_emc_of_match[] = { | 
					
						
							| 
									
										
										
										
											2011-10-17 16:05:22 -07:00
										 |  |  | 	{ .compatible = "nvidia,tegra20-emc", }, | 
					
						
							|  |  |  | 	{ }, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-16 16:54:51 -07:00
										 |  |  | static struct platform_driver tegra_emc_driver = { | 
					
						
							|  |  |  | 	.driver         = { | 
					
						
							|  |  |  | 		.name   = "tegra-emc", | 
					
						
							|  |  |  | 		.owner  = THIS_MODULE, | 
					
						
							| 
									
										
										
										
											2011-10-17 16:05:22 -07:00
										 |  |  | 		.of_match_table = tegra_emc_of_match, | 
					
						
							| 
									
										
										
										
											2011-10-16 16:54:51 -07:00
										 |  |  | 	}, | 
					
						
							|  |  |  | 	.probe          = tegra_emc_probe, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int __init tegra_emc_init(void) | 
					
						
							| 
									
										
										
										
											2011-02-12 18:22:49 -08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-10-16 16:54:51 -07:00
										 |  |  | 	return platform_driver_register(&tegra_emc_driver); | 
					
						
							| 
									
										
										
										
											2011-02-12 18:22:49 -08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2011-10-16 16:54:51 -07:00
										 |  |  | device_initcall(tegra_emc_init); |