xref: /openbmc/linux/drivers/w1/masters/mxc_w1.c (revision e5279ff6)
1a5fd9139SSascha Hauer /*
2a5fd9139SSascha Hauer  * Copyright 2005-2008 Freescale Semiconductor, Inc. All Rights Reserved.
3a5fd9139SSascha Hauer  * Copyright 2008 Luotao Fu, kernel@pengutronix.de
4a5fd9139SSascha Hauer  *
5a5fd9139SSascha Hauer  * This program is free software; you can redistribute it and/or
6a5fd9139SSascha Hauer  * modify it under the terms of the GNU General Public License
7a5fd9139SSascha Hauer  * as published by the Free Software Foundation; either version 2
8a5fd9139SSascha Hauer  * of the License, or (at your option) any later version.
9a5fd9139SSascha Hauer  * This program is distributed in the hope that it will be useful,
10a5fd9139SSascha Hauer  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11a5fd9139SSascha Hauer  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12a5fd9139SSascha Hauer  * GNU General Public License for more details.
13a5fd9139SSascha Hauer  *
14a5fd9139SSascha Hauer  * You should have received a copy of the GNU General Public License
15a5fd9139SSascha Hauer  * along with this program; if not, write to the Free Software
16a5fd9139SSascha Hauer  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17a5fd9139SSascha Hauer  *
18a5fd9139SSascha Hauer  */
19a5fd9139SSascha Hauer 
20a5fd9139SSascha Hauer #include <linux/module.h>
21a5fd9139SSascha Hauer #include <linux/interrupt.h>
22a5fd9139SSascha Hauer #include <linux/platform_device.h>
23a5fd9139SSascha Hauer #include <linux/clk.h>
245a0e3ad6STejun Heo #include <linux/slab.h>
25a5fd9139SSascha Hauer #include <linux/delay.h>
26a5fd9139SSascha Hauer #include <linux/io.h>
27a5fd9139SSascha Hauer 
28a5fd9139SSascha Hauer #include "../w1.h"
29a5fd9139SSascha Hauer #include "../w1_int.h"
30a5fd9139SSascha Hauer #include "../w1_log.h"
31a5fd9139SSascha Hauer 
32a5fd9139SSascha Hauer /* According to the mx27 Datasheet the reset procedure should take up to about
33a5fd9139SSascha Hauer  * 1350us. We set the timeout to 500*100us = 50ms for sure */
34a5fd9139SSascha Hauer #define MXC_W1_RESET_TIMEOUT 500
35a5fd9139SSascha Hauer 
36a5fd9139SSascha Hauer /*
37a5fd9139SSascha Hauer  * MXC W1 Register offsets
38a5fd9139SSascha Hauer  */
39a5fd9139SSascha Hauer #define MXC_W1_CONTROL          0x00
40a5fd9139SSascha Hauer #define MXC_W1_TIME_DIVIDER     0x02
41a5fd9139SSascha Hauer #define MXC_W1_RESET            0x04
42a5fd9139SSascha Hauer #define MXC_W1_COMMAND          0x06
43a5fd9139SSascha Hauer #define MXC_W1_TXRX             0x08
44a5fd9139SSascha Hauer #define MXC_W1_INTERRUPT        0x0A
45a5fd9139SSascha Hauer #define MXC_W1_INTERRUPT_EN     0x0C
46a5fd9139SSascha Hauer 
47a5fd9139SSascha Hauer struct mxc_w1_device {
48a5fd9139SSascha Hauer 	void __iomem *regs;
49a5fd9139SSascha Hauer 	unsigned int clkdiv;
50a5fd9139SSascha Hauer 	struct clk *clk;
51a5fd9139SSascha Hauer 	struct w1_bus_master bus_master;
52a5fd9139SSascha Hauer };
53a5fd9139SSascha Hauer 
54a5fd9139SSascha Hauer /*
55a5fd9139SSascha Hauer  * this is the low level routine to
56a5fd9139SSascha Hauer  * reset the device on the One Wire interface
57a5fd9139SSascha Hauer  * on the hardware
58a5fd9139SSascha Hauer  */
59a5fd9139SSascha Hauer static u8 mxc_w1_ds2_reset_bus(void *data)
60a5fd9139SSascha Hauer {
61a5fd9139SSascha Hauer 	u8 reg_val;
62a5fd9139SSascha Hauer 	unsigned int timeout_cnt = 0;
63a5fd9139SSascha Hauer 	struct mxc_w1_device *dev = data;
64a5fd9139SSascha Hauer 
65a5fd9139SSascha Hauer 	__raw_writeb(0x80, (dev->regs + MXC_W1_CONTROL));
66a5fd9139SSascha Hauer 
67a5fd9139SSascha Hauer 	while (1) {
68a5fd9139SSascha Hauer 		reg_val = __raw_readb(dev->regs + MXC_W1_CONTROL);
69a5fd9139SSascha Hauer 
70a5fd9139SSascha Hauer 		if (((reg_val >> 7) & 0x1) == 0 ||
71a5fd9139SSascha Hauer 		    timeout_cnt > MXC_W1_RESET_TIMEOUT)
72a5fd9139SSascha Hauer 			break;
73a5fd9139SSascha Hauer 		else
74a5fd9139SSascha Hauer 			timeout_cnt++;
75a5fd9139SSascha Hauer 
76a5fd9139SSascha Hauer 		udelay(100);
77a5fd9139SSascha Hauer 	}
78a5fd9139SSascha Hauer 	return (reg_val >> 7) & 0x1;
79a5fd9139SSascha Hauer }
80a5fd9139SSascha Hauer 
81a5fd9139SSascha Hauer /*
82a5fd9139SSascha Hauer  * this is the low level routine to read/write a bit on the One Wire
83a5fd9139SSascha Hauer  * interface on the hardware. It does write 0 if parameter bit is set
84a5fd9139SSascha Hauer  * to 0, otherwise a write 1/read.
85a5fd9139SSascha Hauer  */
86a5fd9139SSascha Hauer static u8 mxc_w1_ds2_touch_bit(void *data, u8 bit)
87a5fd9139SSascha Hauer {
88a5fd9139SSascha Hauer 	struct mxc_w1_device *mdev = data;
89a5fd9139SSascha Hauer 	void __iomem *ctrl_addr = mdev->regs + MXC_W1_CONTROL;
90a5fd9139SSascha Hauer 	unsigned int timeout_cnt = 400; /* Takes max. 120us according to
91a5fd9139SSascha Hauer 					 * datasheet.
92a5fd9139SSascha Hauer 					 */
93a5fd9139SSascha Hauer 
94a5fd9139SSascha Hauer 	__raw_writeb((1 << (5 - bit)), ctrl_addr);
95a5fd9139SSascha Hauer 
96a5fd9139SSascha Hauer 	while (timeout_cnt--) {
97a5fd9139SSascha Hauer 		if (!((__raw_readb(ctrl_addr) >> (5 - bit)) & 0x1))
98a5fd9139SSascha Hauer 			break;
99a5fd9139SSascha Hauer 
100a5fd9139SSascha Hauer 		udelay(1);
101a5fd9139SSascha Hauer 	}
102a5fd9139SSascha Hauer 
103a5fd9139SSascha Hauer 	return ((__raw_readb(ctrl_addr)) >> 3) & 0x1;
104a5fd9139SSascha Hauer }
105a5fd9139SSascha Hauer 
106479e2bceSBill Pemberton static int mxc_w1_probe(struct platform_device *pdev)
107a5fd9139SSascha Hauer {
108a5fd9139SSascha Hauer 	struct mxc_w1_device *mdev;
109a5fd9139SSascha Hauer 	struct resource *res;
110a5fd9139SSascha Hauer 	int err = 0;
111a5fd9139SSascha Hauer 
112e5279ff6SJulia Lawall 	mdev = devm_kzalloc(&pdev->dev, sizeof(struct mxc_w1_device),
113e5279ff6SJulia Lawall 			    GFP_KERNEL);
114a5fd9139SSascha Hauer 	if (!mdev)
115a5fd9139SSascha Hauer 		return -ENOMEM;
116a5fd9139SSascha Hauer 
117e5279ff6SJulia Lawall 	mdev->clk = devm_clk_get(&pdev->dev, NULL);
118e5279ff6SJulia Lawall 	if (IS_ERR(mdev->clk))
119e5279ff6SJulia Lawall 		return PTR_ERR(mdev->clk);
120a5fd9139SSascha Hauer 
121a5fd9139SSascha Hauer 	mdev->clkdiv = (clk_get_rate(mdev->clk) / 1000000) - 1;
122a5fd9139SSascha Hauer 
123e5279ff6SJulia Lawall 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
124e5279ff6SJulia Lawall 	mdev->regs = devm_request_and_ioremap(&pdev->dev, res);
125e5279ff6SJulia Lawall 	if (!mdev->regs)
126e5279ff6SJulia Lawall 		return -EBUSY;
127a5fd9139SSascha Hauer 
12860178b63SSascha Hauer 	clk_prepare_enable(mdev->clk);
129a5fd9139SSascha Hauer 	__raw_writeb(mdev->clkdiv, mdev->regs + MXC_W1_TIME_DIVIDER);
130a5fd9139SSascha Hauer 
131a5fd9139SSascha Hauer 	mdev->bus_master.data = mdev;
132a5fd9139SSascha Hauer 	mdev->bus_master.reset_bus = mxc_w1_ds2_reset_bus;
133a5fd9139SSascha Hauer 	mdev->bus_master.touch_bit = mxc_w1_ds2_touch_bit;
134a5fd9139SSascha Hauer 
135a5fd9139SSascha Hauer 	err = w1_add_master_device(&mdev->bus_master);
136a5fd9139SSascha Hauer 
137a5fd9139SSascha Hauer 	if (err)
138e5279ff6SJulia Lawall 		return err;
139a5fd9139SSascha Hauer 
140a5fd9139SSascha Hauer 	platform_set_drvdata(pdev, mdev);
141a5fd9139SSascha Hauer 	return 0;
142a5fd9139SSascha Hauer }
143a5fd9139SSascha Hauer 
144a5fd9139SSascha Hauer /*
145a5fd9139SSascha Hauer  * disassociate the w1 device from the driver
146a5fd9139SSascha Hauer  */
14782849a93SBill Pemberton static int mxc_w1_remove(struct platform_device *pdev)
148a5fd9139SSascha Hauer {
149a5fd9139SSascha Hauer 	struct mxc_w1_device *mdev = platform_get_drvdata(pdev);
150a5fd9139SSascha Hauer 
151a5fd9139SSascha Hauer 	w1_remove_master_device(&mdev->bus_master);
152a5fd9139SSascha Hauer 
15360178b63SSascha Hauer 	clk_disable_unprepare(mdev->clk);
154a5fd9139SSascha Hauer 
155a5fd9139SSascha Hauer 	platform_set_drvdata(pdev, NULL);
156a5fd9139SSascha Hauer 
157a5fd9139SSascha Hauer 	return 0;
158a5fd9139SSascha Hauer }
159a5fd9139SSascha Hauer 
160a5fd9139SSascha Hauer static struct platform_driver mxc_w1_driver = {
161a5fd9139SSascha Hauer 	.driver = {
162a5fd9139SSascha Hauer 		   .name = "mxc_w1",
163a5fd9139SSascha Hauer 	},
164a5fd9139SSascha Hauer 	.probe = mxc_w1_probe,
16510532fe7SGreg Kroah-Hartman 	.remove = mxc_w1_remove,
166a5fd9139SSascha Hauer };
167fd21bfccSFabio Estevam module_platform_driver(mxc_w1_driver);
168a5fd9139SSascha Hauer 
169a5fd9139SSascha Hauer MODULE_LICENSE("GPL");
170a5fd9139SSascha Hauer MODULE_AUTHOR("Freescale Semiconductors Inc");
171a5fd9139SSascha Hauer MODULE_DESCRIPTION("Driver for One-Wire on MXC");
172