Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

w1: add 1-wire master driver for i.MX27 / i.MX31

This patch adds support for the 1-wire master interface for i.MX27 and
i.MX31.

Signed-off-by: Luotao Fu <l.fu@pengutronix.de>
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Signed-off-by: Evgeniy Polyakov <zbr@ioremap.net>
Cc: Russell King <rmk@arm.linux.org.uk>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Sascha Hauer and committed by
Linus Torvalds
a5fd9139 09f50c95

+232
+2
Documentation/w1/masters/00-INDEX
··· 4 4 - The Maxim/Dallas Semiconductor DS2482 provides 1-wire busses. 5 5 ds2490 6 6 - The Maxim/Dallas Semiconductor DS2490 builds USB <-> W1 bridges. 7 + mxc_w1 8 + - W1 master controller driver found on Freescale MX2/MX3 SoCs 7 9 w1-gpio 8 10 - GPIO 1-wire bus master driver.
+11
Documentation/w1/masters/mxc-w1
··· 1 + Kernel driver mxc_w1 2 + ==================== 3 + 4 + Supported chips: 5 + * Freescale MX27, MX31 and probably other i.MX SoCs 6 + Datasheets: 7 + http://www.freescale.com/files/32bit/doc/data_sheet/MCIMX31.pdf?fpsp=1 8 + http://www.freescale.com/files/dsp/MCIMX27.pdf?fpsp=1 9 + 10 + Author: Originally based on Freescale code, prepared for mainline by 11 + Sascha Hauer <s.hauer@pengutronix.de>
+6
drivers/w1/masters/Kconfig
··· 34 34 This driver can also be built as a module. If so, the module 35 35 will be called ds2482. 36 36 37 + config W1_MASTER_MXC 38 + tristate "Freescale MXC 1-wire busmaster" 39 + depends on W1 && ARCH_MXC 40 + help 41 + Say Y here to enable MXC 1-wire host 42 + 37 43 config W1_MASTER_DS1WM 38 44 tristate "Maxim DS1WM 1-wire busmaster" 39 45 depends on W1 && ARM && HAVE_CLK
+2
drivers/w1/masters/Makefile
··· 5 5 obj-$(CONFIG_W1_MASTER_MATROX) += matrox_w1.o 6 6 obj-$(CONFIG_W1_MASTER_DS2490) += ds2490.o 7 7 obj-$(CONFIG_W1_MASTER_DS2482) += ds2482.o 8 + obj-$(CONFIG_W1_MASTER_MXC) += mxc_w1.o 9 + 8 10 obj-$(CONFIG_W1_MASTER_DS1WM) += ds1wm.o 9 11 obj-$(CONFIG_W1_MASTER_GPIO) += w1-gpio.o 10 12 obj-$(CONFIG_HDQ_MASTER_OMAP) += omap_hdq.o
+211
drivers/w1/masters/mxc_w1.c
··· 1 + /* 2 + * Copyright 2005-2008 Freescale Semiconductor, Inc. All Rights Reserved. 3 + * Copyright 2008 Luotao Fu, kernel@pengutronix.de 4 + * 5 + * This program is free software; you can redistribute it and/or 6 + * modify it under the terms of the GNU General Public License 7 + * as published by the Free Software Foundation; either version 2 8 + * of the License, or (at your option) any later version. 9 + * This program is distributed in the hope that it will be useful, 10 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 + * GNU General Public License for more details. 13 + * 14 + * You should have received a copy of the GNU General Public License 15 + * along with this program; if not, write to the Free Software 16 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 + * 18 + */ 19 + 20 + #include <linux/module.h> 21 + #include <linux/interrupt.h> 22 + #include <linux/platform_device.h> 23 + #include <linux/clk.h> 24 + #include <linux/delay.h> 25 + #include <linux/io.h> 26 + 27 + #include "../w1.h" 28 + #include "../w1_int.h" 29 + #include "../w1_log.h" 30 + 31 + /* According to the mx27 Datasheet the reset procedure should take up to about 32 + * 1350us. We set the timeout to 500*100us = 50ms for sure */ 33 + #define MXC_W1_RESET_TIMEOUT 500 34 + 35 + /* 36 + * MXC W1 Register offsets 37 + */ 38 + #define MXC_W1_CONTROL 0x00 39 + #define MXC_W1_TIME_DIVIDER 0x02 40 + #define MXC_W1_RESET 0x04 41 + #define MXC_W1_COMMAND 0x06 42 + #define MXC_W1_TXRX 0x08 43 + #define MXC_W1_INTERRUPT 0x0A 44 + #define MXC_W1_INTERRUPT_EN 0x0C 45 + 46 + struct mxc_w1_device { 47 + void __iomem *regs; 48 + unsigned int clkdiv; 49 + struct clk *clk; 50 + struct w1_bus_master bus_master; 51 + }; 52 + 53 + /* 54 + * this is the low level routine to 55 + * reset the device on the One Wire interface 56 + * on the hardware 57 + */ 58 + static u8 mxc_w1_ds2_reset_bus(void *data) 59 + { 60 + u8 reg_val; 61 + unsigned int timeout_cnt = 0; 62 + struct mxc_w1_device *dev = data; 63 + 64 + __raw_writeb(0x80, (dev->regs + MXC_W1_CONTROL)); 65 + 66 + while (1) { 67 + reg_val = __raw_readb(dev->regs + MXC_W1_CONTROL); 68 + 69 + if (((reg_val >> 7) & 0x1) == 0 || 70 + timeout_cnt > MXC_W1_RESET_TIMEOUT) 71 + break; 72 + else 73 + timeout_cnt++; 74 + 75 + udelay(100); 76 + } 77 + return (reg_val >> 7) & 0x1; 78 + } 79 + 80 + /* 81 + * this is the low level routine to read/write a bit on the One Wire 82 + * interface on the hardware. It does write 0 if parameter bit is set 83 + * to 0, otherwise a write 1/read. 84 + */ 85 + static u8 mxc_w1_ds2_touch_bit(void *data, u8 bit) 86 + { 87 + struct mxc_w1_device *mdev = data; 88 + void __iomem *ctrl_addr = mdev->regs + MXC_W1_CONTROL; 89 + unsigned int timeout_cnt = 400; /* Takes max. 120us according to 90 + * datasheet. 91 + */ 92 + 93 + __raw_writeb((1 << (5 - bit)), ctrl_addr); 94 + 95 + while (timeout_cnt--) { 96 + if (!((__raw_readb(ctrl_addr) >> (5 - bit)) & 0x1)) 97 + break; 98 + 99 + udelay(1); 100 + } 101 + 102 + return ((__raw_readb(ctrl_addr)) >> 3) & 0x1; 103 + } 104 + 105 + static int __init mxc_w1_probe(struct platform_device *pdev) 106 + { 107 + struct mxc_w1_device *mdev; 108 + struct resource *res; 109 + int err = 0; 110 + 111 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 112 + if (!res) 113 + return -ENODEV; 114 + 115 + mdev = kzalloc(sizeof(struct mxc_w1_device), GFP_KERNEL); 116 + if (!mdev) 117 + return -ENOMEM; 118 + 119 + mdev->clk = clk_get(&pdev->dev, "owire_clk"); 120 + if (!mdev->clk) { 121 + err = -ENODEV; 122 + goto failed_clk; 123 + } 124 + 125 + mdev->clkdiv = (clk_get_rate(mdev->clk) / 1000000) - 1; 126 + 127 + res = request_mem_region(res->start, resource_size(res), 128 + "mxc_w1"); 129 + if (!res) { 130 + err = -EBUSY; 131 + goto failed_req; 132 + } 133 + 134 + mdev->regs = ioremap(res->start, resource_size(res)); 135 + if (!mdev->regs) { 136 + printk(KERN_ERR "Cannot map frame buffer registers\n"); 137 + goto failed_ioremap; 138 + } 139 + 140 + clk_enable(mdev->clk); 141 + __raw_writeb(mdev->clkdiv, mdev->regs + MXC_W1_TIME_DIVIDER); 142 + 143 + mdev->bus_master.data = mdev; 144 + mdev->bus_master.reset_bus = mxc_w1_ds2_reset_bus; 145 + mdev->bus_master.touch_bit = mxc_w1_ds2_touch_bit; 146 + 147 + err = w1_add_master_device(&mdev->bus_master); 148 + 149 + if (err) 150 + goto failed_add; 151 + 152 + platform_set_drvdata(pdev, mdev); 153 + return 0; 154 + 155 + failed_add: 156 + iounmap(mdev->regs); 157 + failed_ioremap: 158 + release_mem_region(res->start, resource_size(res)); 159 + failed_req: 160 + clk_put(mdev->clk); 161 + failed_clk: 162 + kfree(mdev); 163 + return err; 164 + } 165 + 166 + /* 167 + * disassociate the w1 device from the driver 168 + */ 169 + static int mxc_w1_remove(struct platform_device *pdev) 170 + { 171 + struct mxc_w1_device *mdev = platform_get_drvdata(pdev); 172 + struct resource *res; 173 + 174 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 175 + 176 + w1_remove_master_device(&mdev->bus_master); 177 + 178 + iounmap(mdev->regs); 179 + release_mem_region(res->start, resource_size(res)); 180 + clk_disable(mdev->clk); 181 + clk_put(mdev->clk); 182 + 183 + platform_set_drvdata(pdev, NULL); 184 + 185 + return 0; 186 + } 187 + 188 + static struct platform_driver mxc_w1_driver = { 189 + .driver = { 190 + .name = "mxc_w1", 191 + }, 192 + .probe = mxc_w1_probe, 193 + .remove = mxc_w1_remove, 194 + }; 195 + 196 + static int __init mxc_w1_init(void) 197 + { 198 + return platform_driver_register(&mxc_w1_driver); 199 + } 200 + 201 + static void mxc_w1_exit(void) 202 + { 203 + platform_driver_unregister(&mxc_w1_driver); 204 + } 205 + 206 + module_init(mxc_w1_init); 207 + module_exit(mxc_w1_exit); 208 + 209 + MODULE_LICENSE("GPL"); 210 + MODULE_AUTHOR("Freescale Semiconductors Inc"); 211 + MODULE_DESCRIPTION("Driver for One-Wire on MXC");