Skip to content

Commit a5fd913

Browse files
saschahauertorvalds
authored andcommitted
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 <[email protected]> Signed-off-by: Sascha Hauer <[email protected]> Signed-off-by: Evgeniy Polyakov <[email protected]> Cc: Russell King <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent 09f50c9 commit a5fd913

File tree

5 files changed

+232
-0
lines changed

5 files changed

+232
-0
lines changed

Documentation/w1/masters/00-INDEX

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,7 @@ ds2482
44
- The Maxim/Dallas Semiconductor DS2482 provides 1-wire busses.
55
ds2490
66
- The Maxim/Dallas Semiconductor DS2490 builds USB <-> W1 bridges.
7+
mxc_w1
8+
- W1 master controller driver found on Freescale MX2/MX3 SoCs
79
w1-gpio
810
- GPIO 1-wire bus master driver.

Documentation/w1/masters/mxc-w1

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
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 <[email protected]>

drivers/w1/masters/Kconfig

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,12 @@ config W1_MASTER_DS2482
3434
This driver can also be built as a module. If so, the module
3535
will be called ds2482.
3636

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+
3743
config W1_MASTER_DS1WM
3844
tristate "Maxim DS1WM 1-wire busmaster"
3945
depends on W1 && ARM && HAVE_CLK

drivers/w1/masters/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
obj-$(CONFIG_W1_MASTER_MATROX) += matrox_w1.o
66
obj-$(CONFIG_W1_MASTER_DS2490) += ds2490.o
77
obj-$(CONFIG_W1_MASTER_DS2482) += ds2482.o
8+
obj-$(CONFIG_W1_MASTER_MXC) += mxc_w1.o
9+
810
obj-$(CONFIG_W1_MASTER_DS1WM) += ds1wm.o
911
obj-$(CONFIG_W1_MASTER_GPIO) += w1-gpio.o
1012
obj-$(CONFIG_HDQ_MASTER_OMAP) += omap_hdq.o

drivers/w1/masters/mxc_w1.c

Lines changed: 211 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
/*
2+
* Copyright 2005-2008 Freescale Semiconductor, Inc. All Rights Reserved.
3+
* Copyright 2008 Luotao Fu, [email protected]
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");

0 commit comments

Comments
 (0)