1
2
3
4
5
6
7
8
9
10
11
12
13
14
15#include <linux/clk.h>
16#include <linux/delay.h>
17#include <linux/io.h>
18#include <linux/jiffies.h>
19#include <linux/module.h>
20#include <linux/platform_device.h>
21
22#include "../w1.h"
23#include "../w1_int.h"
24
25
26
27
28#define MXC_W1_CONTROL 0x00
29# define MXC_W1_CONTROL_RDST BIT(3)
30# define MXC_W1_CONTROL_WR(x) BIT(5 - (x))
31# define MXC_W1_CONTROL_PST BIT(6)
32# define MXC_W1_CONTROL_RPP BIT(7)
33#define MXC_W1_TIME_DIVIDER 0x02
34#define MXC_W1_RESET 0x04
35# define MXC_W1_RESET_RST BIT(0)
36
37struct mxc_w1_device {
38 void __iomem *regs;
39 struct clk *clk;
40 struct w1_bus_master bus_master;
41};
42
43
44
45
46
47
48static u8 mxc_w1_ds2_reset_bus(void *data)
49{
50 struct mxc_w1_device *dev = data;
51 unsigned long timeout;
52
53 writeb(MXC_W1_CONTROL_RPP, dev->regs + MXC_W1_CONTROL);
54
55
56 timeout = jiffies + usecs_to_jiffies(1500);
57
58 udelay(511 + 512);
59
60 do {
61 u8 ctrl = readb(dev->regs + MXC_W1_CONTROL);
62
63
64 if (!(ctrl & MXC_W1_CONTROL_RPP))
65 return !(ctrl & MXC_W1_CONTROL_PST);
66 } while (time_is_after_jiffies(timeout));
67
68 return 1;
69}
70
71
72
73
74
75
76static u8 mxc_w1_ds2_touch_bit(void *data, u8 bit)
77{
78 struct mxc_w1_device *dev = data;
79 unsigned long timeout;
80
81 writeb(MXC_W1_CONTROL_WR(bit), dev->regs + MXC_W1_CONTROL);
82
83
84 timeout = jiffies + usecs_to_jiffies(200);
85
86 udelay(60);
87
88 do {
89 u8 ctrl = readb(dev->regs + MXC_W1_CONTROL);
90
91
92 if (!(ctrl & MXC_W1_CONTROL_WR(bit)))
93 return !!(ctrl & MXC_W1_CONTROL_RDST);
94 } while (time_is_after_jiffies(timeout));
95
96 return 0;
97}
98
99static int mxc_w1_probe(struct platform_device *pdev)
100{
101 struct mxc_w1_device *mdev;
102 unsigned long clkrate;
103 struct resource *res;
104 unsigned int clkdiv;
105 int err;
106
107 mdev = devm_kzalloc(&pdev->dev, sizeof(struct mxc_w1_device),
108 GFP_KERNEL);
109 if (!mdev)
110 return -ENOMEM;
111
112 mdev->clk = devm_clk_get(&pdev->dev, NULL);
113 if (IS_ERR(mdev->clk))
114 return PTR_ERR(mdev->clk);
115
116 clkrate = clk_get_rate(mdev->clk);
117 if (clkrate < 10000000)
118 dev_warn(&pdev->dev,
119 "Low clock frequency causes improper function\n");
120
121 clkdiv = DIV_ROUND_CLOSEST(clkrate, 1000000);
122 clkrate /= clkdiv;
123 if ((clkrate < 980000) || (clkrate > 1020000))
124 dev_warn(&pdev->dev,
125 "Incorrect time base frequency %lu Hz\n", clkrate);
126
127 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
128 mdev->regs = devm_ioremap_resource(&pdev->dev, res);
129 if (IS_ERR(mdev->regs))
130 return PTR_ERR(mdev->regs);
131
132 err = clk_prepare_enable(mdev->clk);
133 if (err)
134 return err;
135
136
137 writeb(MXC_W1_RESET_RST, mdev->regs + MXC_W1_RESET);
138 writeb(0, mdev->regs + MXC_W1_RESET);
139
140 writeb(clkdiv - 1, mdev->regs + MXC_W1_TIME_DIVIDER);
141
142 mdev->bus_master.data = mdev;
143 mdev->bus_master.reset_bus = mxc_w1_ds2_reset_bus;
144 mdev->bus_master.touch_bit = mxc_w1_ds2_touch_bit;
145
146 platform_set_drvdata(pdev, mdev);
147
148 err = w1_add_master_device(&mdev->bus_master);
149 if (err)
150 clk_disable_unprepare(mdev->clk);
151
152 return err;
153}
154
155
156
157
158static int mxc_w1_remove(struct platform_device *pdev)
159{
160 struct mxc_w1_device *mdev = platform_get_drvdata(pdev);
161
162 w1_remove_master_device(&mdev->bus_master);
163
164 clk_disable_unprepare(mdev->clk);
165
166 return 0;
167}
168
169static const struct of_device_id mxc_w1_dt_ids[] = {
170 { .compatible = "fsl,imx21-owire" },
171 { }
172};
173MODULE_DEVICE_TABLE(of, mxc_w1_dt_ids);
174
175static struct platform_driver mxc_w1_driver = {
176 .driver = {
177 .name = "mxc_w1",
178 .of_match_table = mxc_w1_dt_ids,
179 },
180 .probe = mxc_w1_probe,
181 .remove = mxc_w1_remove,
182};
183module_platform_driver(mxc_w1_driver);
184
185MODULE_LICENSE("GPL");
186MODULE_AUTHOR("Freescale Semiconductors Inc");
187MODULE_DESCRIPTION("Driver for One-Wire on MXC");
188