2 * Copyright 2005-2008 Freescale Semiconductor, Inc. All Rights Reserved.
3 * Copyright 2008 Luotao Fu, kernel@pengutronix.de
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.
15 #include <linux/clk.h>
16 #include <linux/delay.h>
18 #include <linux/module.h>
19 #include <linux/platform_device.h>
22 #include "../w1_int.h"
24 /* According to the mx27 Datasheet the reset procedure should take up to about
25 * 1350us. We set the timeout to 500*100us = 50ms for sure */
26 #define MXC_W1_RESET_TIMEOUT 500
29 * MXC W1 Register offsets
31 #define MXC_W1_CONTROL 0x00
32 # define MXC_W1_CONTROL_RDST BIT(3)
33 # define MXC_W1_CONTROL_WR(x) BIT(5 - (x))
34 # define MXC_W1_CONTROL_PST BIT(6)
35 # define MXC_W1_CONTROL_RPP BIT(7)
36 #define MXC_W1_TIME_DIVIDER 0x02
37 #define MXC_W1_RESET 0x04
39 struct mxc_w1_device {
42 struct w1_bus_master bus_master;
46 * this is the low level routine to
47 * reset the device on the One Wire interface
50 static u8 mxc_w1_ds2_reset_bus(void *data)
53 unsigned int timeout_cnt = 0;
54 struct mxc_w1_device *dev = data;
56 writeb(MXC_W1_CONTROL_RPP, (dev->regs + MXC_W1_CONTROL));
59 reg_val = readb(dev->regs + MXC_W1_CONTROL);
61 if (!(reg_val & MXC_W1_CONTROL_RPP) ||
62 timeout_cnt > MXC_W1_RESET_TIMEOUT)
69 return !!(reg_val & MXC_W1_CONTROL_PST);
73 * this is the low level routine to read/write a bit on the One Wire
74 * interface on the hardware. It does write 0 if parameter bit is set
75 * to 0, otherwise a write 1/read.
77 static u8 mxc_w1_ds2_touch_bit(void *data, u8 bit)
79 struct mxc_w1_device *mdev = data;
80 void __iomem *ctrl_addr = mdev->regs + MXC_W1_CONTROL;
81 unsigned int timeout_cnt = 400; /* Takes max. 120us according to
85 writeb(MXC_W1_CONTROL_WR(bit), ctrl_addr);
87 while (timeout_cnt--) {
88 if (!(readb(ctrl_addr) & MXC_W1_CONTROL_WR(bit)))
94 return !!(readb(ctrl_addr) & MXC_W1_CONTROL_RDST);
97 static int mxc_w1_probe(struct platform_device *pdev)
99 struct mxc_w1_device *mdev;
100 unsigned long clkrate;
101 struct resource *res;
105 mdev = devm_kzalloc(&pdev->dev, sizeof(struct mxc_w1_device),
110 mdev->clk = devm_clk_get(&pdev->dev, NULL);
111 if (IS_ERR(mdev->clk))
112 return PTR_ERR(mdev->clk);
114 clkrate = clk_get_rate(mdev->clk);
115 if (clkrate < 10000000)
117 "Low clock frequency causes improper function\n");
119 clkdiv = DIV_ROUND_CLOSEST(clkrate, 1000000);
121 if ((clkrate < 980000) || (clkrate > 1020000))
123 "Incorrect time base frequency %lu Hz\n", clkrate);
125 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
126 mdev->regs = devm_ioremap_resource(&pdev->dev, res);
127 if (IS_ERR(mdev->regs))
128 return PTR_ERR(mdev->regs);
130 err = clk_prepare_enable(mdev->clk);
134 writeb(clkdiv - 1, mdev->regs + MXC_W1_TIME_DIVIDER);
136 mdev->bus_master.data = mdev;
137 mdev->bus_master.reset_bus = mxc_w1_ds2_reset_bus;
138 mdev->bus_master.touch_bit = mxc_w1_ds2_touch_bit;
140 platform_set_drvdata(pdev, mdev);
142 err = w1_add_master_device(&mdev->bus_master);
144 clk_disable_unprepare(mdev->clk);
150 * disassociate the w1 device from the driver
152 static int mxc_w1_remove(struct platform_device *pdev)
154 struct mxc_w1_device *mdev = platform_get_drvdata(pdev);
156 w1_remove_master_device(&mdev->bus_master);
158 clk_disable_unprepare(mdev->clk);
163 static struct of_device_id mxc_w1_dt_ids[] = {
164 { .compatible = "fsl,imx21-owire" },
167 MODULE_DEVICE_TABLE(of, mxc_w1_dt_ids);
169 static struct platform_driver mxc_w1_driver = {
172 .owner = THIS_MODULE,
173 .of_match_table = mxc_w1_dt_ids,
175 .probe = mxc_w1_probe,
176 .remove = mxc_w1_remove,
178 module_platform_driver(mxc_w1_driver);
180 MODULE_LICENSE("GPL");
181 MODULE_AUTHOR("Freescale Semiconductors Inc");
182 MODULE_DESCRIPTION("Driver for One-Wire on MXC");