From 394c6535f18005ca80336b1b7128b488243e0381 Mon Sep 17 00:00:00 2001 From: Hoang Pham Date: Thu, 4 Feb 2010 20:32:12 -0800 Subject: tegra: Add 1-wire bus master driver for Tegra SOCs Fix logic pinmux config select Change-Id: I49f8c399d57455c85ed373a66db6696cdd997bec --- arch/arm/configs/tegra_whistler_android_defconfig | 23 ++- arch/arm/mach-tegra/include/mach/nvrm_linux.h | 1 + arch/arm/mach-tegra/include/nvodm_query_pinmux.h | 21 ++ arch/arm/mach-tegra/init_common.c | 37 ++++ drivers/w1/masters/Kconfig | 7 + drivers/w1/masters/Makefile | 1 + drivers/w1/masters/tegra_w1.c | 222 ++++++++++++++++++++++ include/linux/tegra_devices.h | 7 + 8 files changed, 317 insertions(+), 2 deletions(-) create mode 100644 drivers/w1/masters/tegra_w1.c diff --git a/arch/arm/configs/tegra_whistler_android_defconfig b/arch/arm/configs/tegra_whistler_android_defconfig index 6e341676dba1..868c3471983e 100644 --- a/arch/arm/configs/tegra_whistler_android_defconfig +++ b/arch/arm/configs/tegra_whistler_android_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit # Linux kernel version: 2.6.29 -# Mon Jan 18 12:46:38 2010 +# Thu Jan 28 11:24:02 2010 # CONFIG_ARM=y CONFIG_SYS_SUPPORTS_APM_EMULATION=y @@ -871,7 +871,26 @@ CONFIG_SPI_TEGRA=y # # CONFIG_SPI_SPIDEV is not set # CONFIG_SPI_TLE62X0 is not set -# CONFIG_W1 is not set +CONFIG_W1=y + +# +# 1-wire Bus Masters +# +# CONFIG_W1_MASTER_DS2490 is not set +# CONFIG_W1_MASTER_DS2482 is not set +CONFIG_W1_MASTER_TEGRA=y +# CONFIG_W1_MASTER_DS1WM is not set +# CONFIG_W1_MASTER_GPIO is not set + +# +# 1-wire Slaves +# +# CONFIG_W1_SLAVE_THERM is not set +# CONFIG_W1_SLAVE_SMEM is not set +# CONFIG_W1_SLAVE_DS2431 is not set +# CONFIG_W1_SLAVE_DS2433 is not set +# CONFIG_W1_SLAVE_DS2760 is not set +# CONFIG_W1_SLAVE_BQ27000 is not set CONFIG_POWER_SUPPLY=y # CONFIG_POWER_SUPPLY_DEBUG is not set # CONFIG_PDA_POWER is not set diff --git a/arch/arm/mach-tegra/include/mach/nvrm_linux.h b/arch/arm/mach-tegra/include/mach/nvrm_linux.h index 035de018f01d..cdf00221dc48 100644 --- a/arch/arm/mach-tegra/include/mach/nvrm_linux.h +++ b/arch/arm/mach-tegra/include/mach/nvrm_linux.h @@ -48,6 +48,7 @@ #include #include +#include #include #include #include diff --git a/arch/arm/mach-tegra/include/nvodm_query_pinmux.h b/arch/arm/mach-tegra/include/nvodm_query_pinmux.h index c0b2e48cb134..5365201b8457 100644 --- a/arch/arm/mach-tegra/include/nvodm_query_pinmux.h +++ b/arch/arm/mach-tegra/include/nvodm_query_pinmux.h @@ -193,6 +193,27 @@ typedef enum NvOdmHsmmcPinMap_Force32 = 0x7FFFFFFF, } NvOdmHsmmcPinMap; +/** + * Defines the OWR pin-mux configurations. + */ +typedef enum +{ + NvOdmOwrPinMap_Config1 = 1, + NvOdmOwrPinMap_Config2, + NvOdmOwrPinMap_Config3, + + /** + * This configuration disables (tristates) OWR pins. This option may be + * used to change which pins an attached OWR device is using at runtime. + * In some cases, one device might set up OWR, communicate across this bus, + * and then set the OWR bus configuration to "multiplexed" so that another + * device can opt to use OWR with its own configurations at a later time. + */ + NvOdmOwrPinMap_Multiplexed = NVODM_QUERY_PINMAP_MULTIPLEXED, + /** Ignore -- Forces compilers to make 32-bit enums. */ + NvOdmOwrPinMap_Force32 = 0x7FFFFFFF, +} NvOdmOwrPinMap; + /** * Defines I2C pin-mux configurations. */ diff --git a/arch/arm/mach-tegra/init_common.c b/arch/arm/mach-tegra/init_common.c index 97809fc0d086..b054a1bf40af 100755 --- a/arch/arm/mach-tegra/init_common.c +++ b/arch/arm/mach-tegra/init_common.c @@ -256,6 +256,42 @@ static void __init tegra_register_spi(void) } #endif +#if !defined(CONFIG_W1_MASTER_TEGRA) +#define tegra_register_w1() do { } while (0) +#else +static void __init tegra_register_w1(void) +{ + const NvU32 *pPinMuxes; + NvU32 NumPinMuxes, NumModules; + struct platform_device *pDev; + struct tegra_w1_platform_data W1Data; + NvU32 i; + + NumModules = NvRmModuleGetNumInstances(s_hRmGlobal, NvOdmIoModule_OneWire); + NvOdmQueryPinMux(NvOdmIoModule_OneWire, &pPinMuxes, &NumPinMuxes); + + for (i=0; i < NumModules && i < NumPinMuxes; i++) + { + if (!pPinMuxes[i]) + continue; + + pDev = platform_device_alloc("tegra_w1", i); + if (!pDev) + goto fail; + W1Data.Instance = i; + W1Data.PinMuxConfig = pPinMuxes[i]; + if (platform_device_add_data(pDev, &W1Data, sizeof(W1Data))) + goto fail; + if (platform_device_add(pDev)) + goto fail; + } + return; +fail: + if (pDev) + platform_device_del(pDev); +} +#endif + #if !defined(CONFIG_I2C_TEGRA) #define tegra_register_i2c() do { } while (0) #else @@ -873,6 +909,7 @@ void __init tegra_common_init(void) tegra_register_uart(); tegra_register_sdio(); tegra_register_usb(); + tegra_register_w1(); #ifdef CONFIG_PM /* FIXME : Uncomment this for actual suspend/resume tegra_set_suspend_ops(); */ diff --git a/drivers/w1/masters/Kconfig b/drivers/w1/masters/Kconfig index 96d2f8e4c275..5bad3a3effac 100644 --- a/drivers/w1/masters/Kconfig +++ b/drivers/w1/masters/Kconfig @@ -40,6 +40,13 @@ config W1_MASTER_MXC help Say Y here to enable MXC 1-wire host +config W1_MASTER_TEGRA + boolean "NVIDIA Tegra internal 1-wire controller" + depends on W1 && ARCH_TEGRA + help + If you say yes to this option, support will be included for the + 1-wire controller embedded in NVIDIA Tegra SOCs + config W1_MASTER_DS1WM tristate "Maxim DS1WM 1-wire busmaster" depends on W1 && ARM && HAVE_CLK diff --git a/drivers/w1/masters/Makefile b/drivers/w1/masters/Makefile index c5a3e96fcbab..45eeae881ee7 100644 --- a/drivers/w1/masters/Makefile +++ b/drivers/w1/masters/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_W1_MASTER_MATROX) += matrox_w1.o obj-$(CONFIG_W1_MASTER_DS2490) += ds2490.o obj-$(CONFIG_W1_MASTER_DS2482) += ds2482.o obj-$(CONFIG_W1_MASTER_MXC) += mxc_w1.o +obj-$(CONFIG_W1_MASTER_TEGRA) += tegra_w1.o obj-$(CONFIG_W1_MASTER_DS1WM) += ds1wm.o obj-$(CONFIG_W1_MASTER_GPIO) += w1-gpio.o diff --git a/drivers/w1/masters/tegra_w1.c b/drivers/w1/masters/tegra_w1.c new file mode 100644 index 000000000000..f0418da1c5b8 --- /dev/null +++ b/drivers/w1/masters/tegra_w1.c @@ -0,0 +1,222 @@ +/* + * drivers/w1/masters/tegra-w1.c + * + * ONE WIRE (OWR) bus driver for internal OWR controllers in NVIDIA Tegra SoCs + * + * Copyright (C) 2010 NVIDIA Corporation + * + * 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; either version 2 of the License, or (at your + * option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../w1.h" +#include "../w1_int.h" +#include "../w1_log.h" + +#include +#include +#include +#include + +struct tegra_w1_dev +{ + NvRmOwrHandle OwrHandle; + NvOdmOwrPinMap pin_map; + struct w1_bus_master bus_master; +}; + +static u8 tegra_w1_read_byte(void *data) +{ + struct tegra_w1_dev *dev = data; + NvRmOwrTransactionInfo tInfo; + NvError err; + u8 buffer[1]; + + tInfo.Flags = NvRmOwr_ReadByte; + tInfo.NumBytes = 1; + tInfo.Address = 0; + tInfo.Offset = 0; + + err = NvRmOwrTransaction(dev->OwrHandle, dev->pin_map, + buffer, tInfo.NumBytes, &tInfo, 1); + if (err != NvSuccess) + { + printk(KERN_ERR "tegra_w1_read_byte failed 0x%x\r\n", err); + err = -EIO; + } + + if (!err) + return buffer[0]; + else + return 0; +} + +static void tegra_w1_write_byte(void *data, u8 a_byte) +{ + struct tegra_w1_dev *dev = data; + NvRmOwrTransactionInfo tInfo; + NvError err; + u8 buffer[1]; + + tInfo.Flags = NvRmOwr_WriteByte; + tInfo.NumBytes = 1; + tInfo.Address = 0; + tInfo.Offset = 0; + buffer[0] = a_byte; + + err = NvRmOwrTransaction(dev->OwrHandle, dev->pin_map, + buffer, tInfo.NumBytes, &tInfo, 1); + if (err != NvSuccess) + { + printk(KERN_ERR "tegra_w1_write_byte failed 0x%x\r\n", err); + err = -EIO; + } +} + +static u8 tegra_w1_reset_bus(void *data) +{ + struct tegra_w1_dev *dev = data; + NvRmOwrTransactionInfo tInfo; + NvError err; + u8 buffer[1]; + + tInfo.Flags = NvRmOwr_CheckPresence; + tInfo.NumBytes = 1; + tInfo.Address = 0; + tInfo.Offset = 0; + + err = NvRmOwrTransaction(dev->OwrHandle, dev->pin_map, + buffer, tInfo.NumBytes, &tInfo, 1); + if (err != NvSuccess) + { + printk(KERN_ERR "tegra_w1_reset_bus failed 0x%x\r\n", err); + err = -EIO; + } + + if (!err) + { + /* Device present */ + return 0; + } + else + { + /* No Device present */ + return 1; + } +} + +static int tegra_w1_probe(struct platform_device *pdev) +{ + struct tegra_w1_dev *dev; + struct tegra_w1_platform_data *pdata = pdev->dev.platform_data; + int ret; + NvError err; + + printk(KERN_INFO "tegra_w1_probe\r\n"); + printk(KERN_INFO "Instance = %d, PinMuxConfig = %d\r\n", + pdata->Instance, pdata->PinMuxConfig); + + if (pdata == NULL) + return -ENODEV; + + dev = kzalloc(sizeof(struct tegra_w1_dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + + err = NvRmOwrOpen(s_hRmGlobal, pdata->Instance, &dev->OwrHandle); + if (err) + { + ret = -ENODEV; + printk(KERN_INFO "Failed to open NvRmOwrOpen - returned %d\n", err); + goto err_rmapi_failed; + } + + dev->pin_map = pdata->PinMuxConfig; + dev->bus_master.data = dev; + dev->bus_master.read_byte = tegra_w1_read_byte; + dev->bus_master.write_byte = tegra_w1_write_byte; + dev->bus_master.reset_bus = tegra_w1_reset_bus; + + ret = w1_add_master_device(&dev->bus_master); + if (ret) + { + printk(KERN_INFO "w1_add_master_device - failed %d\r\n", ret); + goto err_w1_add_master_device_failed; + } + + platform_set_drvdata(pdev, dev); + + return 0; + +err_rmapi_failed: +err_w1_add_master_device_failed: + kfree(dev); + return ret; +} + +static int +tegra_w1_remove(struct platform_device *pdev) +{ + struct tegra_w1_dev *dev = platform_get_drvdata(pdev); + + NvRmOwrClose(dev->OwrHandle); + w1_remove_master_device(&dev->bus_master); + platform_set_drvdata(pdev, NULL); + kfree(dev); + return 0; +} + +static int tegra_w1_suspend(struct platform_device *pdev, pm_message_t state) +{ + return 0; +} + +static int tegra_w1_resume(struct platform_device *pdev) +{ + return 0; +} + +static struct platform_driver tegra_w1_driver = { + .probe = tegra_w1_probe, + .remove = tegra_w1_remove, + .suspend = tegra_w1_suspend, + .resume = tegra_w1_resume, + .driver = + { + .name = "tegra_w1", + .owner = THIS_MODULE, + }, +}; + +static int __init +tegra_w1_init(void) +{ + return platform_driver_register(&tegra_w1_driver); +} +module_init(tegra_w1_init); + +static void __exit tegra_w1_exit(void) +{ + platform_driver_unregister(&tegra_w1_driver); +} +module_exit(tegra_w1_exit); diff --git a/include/linux/tegra_devices.h b/include/linux/tegra_devices.h index 143037a4a64e..adbfffe92f53 100755 --- a/include/linux/tegra_devices.h +++ b/include/linux/tegra_devices.h @@ -66,6 +66,13 @@ struct tegra_i2c_platform_data { NvOdmI2cPinMap PinMuxConfig; }; +/* Platfrom data for W1 bus driver */ +struct tegra_w1_platform_data { + NvU32 Instance; + NvOdmOwrPinMap PinMuxConfig; +}; + + /* Platfrom data for SPI bus driver */ struct tegra_spi_platform_data { NvU32 IoModuleID; -- cgit v1.2.3