blob: 67b067a3e2abbcddadd60a4b9051fb23e5392f45 [file] [log] [blame]
Sascha Hauera5fd9132009-01-07 18:08:58 -08001/*
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.
Sascha Hauera5fd9132009-01-07 18:08:58 -080013 */
14
Sascha Hauera5fd9132009-01-07 18:08:58 -080015#include <linux/clk.h>
16#include <linux/delay.h>
17#include <linux/io.h>
Alexander Shiyan18fd9e3592014-02-22 11:29:50 +040018#include <linux/module.h>
19#include <linux/platform_device.h>
Sascha Hauera5fd9132009-01-07 18:08:58 -080020
21#include "../w1.h"
22#include "../w1_int.h"
Sascha Hauera5fd9132009-01-07 18:08:58 -080023
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
27
28/*
29 * MXC W1 Register offsets
30 */
Alexander Shiyan18fd9e3592014-02-22 11:29:50 +040031#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
Sascha Hauera5fd9132009-01-07 18:08:58 -080038
39struct mxc_w1_device {
40 void __iomem *regs;
Sascha Hauera5fd9132009-01-07 18:08:58 -080041 struct clk *clk;
42 struct w1_bus_master bus_master;
43};
44
45/*
46 * this is the low level routine to
47 * reset the device on the One Wire interface
48 * on the hardware
49 */
50static u8 mxc_w1_ds2_reset_bus(void *data)
51{
52 u8 reg_val;
53 unsigned int timeout_cnt = 0;
54 struct mxc_w1_device *dev = data;
55
Alexander Shiyanfc945d62014-02-22 11:29:51 +040056 writeb(MXC_W1_CONTROL_RPP, (dev->regs + MXC_W1_CONTROL));
Sascha Hauera5fd9132009-01-07 18:08:58 -080057
58 while (1) {
Alexander Shiyanfc945d62014-02-22 11:29:51 +040059 reg_val = readb(dev->regs + MXC_W1_CONTROL);
Sascha Hauera5fd9132009-01-07 18:08:58 -080060
Alexander Shiyan18fd9e3592014-02-22 11:29:50 +040061 if (!(reg_val & MXC_W1_CONTROL_RPP) ||
Sascha Hauera5fd9132009-01-07 18:08:58 -080062 timeout_cnt > MXC_W1_RESET_TIMEOUT)
63 break;
64 else
65 timeout_cnt++;
66
67 udelay(100);
68 }
Alexander Shiyan18fd9e3592014-02-22 11:29:50 +040069 return !!(reg_val & MXC_W1_CONTROL_PST);
Sascha Hauera5fd9132009-01-07 18:08:58 -080070}
71
72/*
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.
76 */
77static u8 mxc_w1_ds2_touch_bit(void *data, u8 bit)
78{
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
82 * datasheet.
83 */
84
Alexander Shiyanfc945d62014-02-22 11:29:51 +040085 writeb(MXC_W1_CONTROL_WR(bit), ctrl_addr);
Sascha Hauera5fd9132009-01-07 18:08:58 -080086
87 while (timeout_cnt--) {
Alexander Shiyanfc945d62014-02-22 11:29:51 +040088 if (!(readb(ctrl_addr) & MXC_W1_CONTROL_WR(bit)))
Sascha Hauera5fd9132009-01-07 18:08:58 -080089 break;
90
91 udelay(1);
92 }
93
Alexander Shiyanfc945d62014-02-22 11:29:51 +040094 return !!(readb(ctrl_addr) & MXC_W1_CONTROL_RDST);
Sascha Hauera5fd9132009-01-07 18:08:58 -080095}
96
Bill Pemberton479e2bc2012-11-19 13:21:43 -050097static int mxc_w1_probe(struct platform_device *pdev)
Sascha Hauera5fd9132009-01-07 18:08:58 -080098{
99 struct mxc_w1_device *mdev;
Alexander Shiyan71531f52013-11-29 15:39:29 +0400100 unsigned long clkrate;
Sascha Hauera5fd9132009-01-07 18:08:58 -0800101 struct resource *res;
Alexander Shiyana0822632013-11-29 15:39:28 +0400102 unsigned int clkdiv;
Alexander Shiyan001d1952013-11-29 15:39:30 +0400103 int err;
Sascha Hauera5fd9132009-01-07 18:08:58 -0800104
Julia Lawalle5279ff2012-12-07 00:15:24 +0100105 mdev = devm_kzalloc(&pdev->dev, sizeof(struct mxc_w1_device),
106 GFP_KERNEL);
Sascha Hauera5fd9132009-01-07 18:08:58 -0800107 if (!mdev)
108 return -ENOMEM;
109
Julia Lawalle5279ff2012-12-07 00:15:24 +0100110 mdev->clk = devm_clk_get(&pdev->dev, NULL);
111 if (IS_ERR(mdev->clk))
112 return PTR_ERR(mdev->clk);
Sascha Hauera5fd9132009-01-07 18:08:58 -0800113
Alexander Shiyan71531f52013-11-29 15:39:29 +0400114 clkrate = clk_get_rate(mdev->clk);
115 if (clkrate < 10000000)
116 dev_warn(&pdev->dev,
117 "Low clock frequency causes improper function\n");
118
119 clkdiv = DIV_ROUND_CLOSEST(clkrate, 1000000);
120 clkrate /= clkdiv;
121 if ((clkrate < 980000) || (clkrate > 1020000))
122 dev_warn(&pdev->dev,
123 "Incorrect time base frequency %lu Hz\n", clkrate);
Sascha Hauera5fd9132009-01-07 18:08:58 -0800124
Julia Lawalle5279ff2012-12-07 00:15:24 +0100125 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Fabio Estevam388f7bd2013-03-11 20:18:15 -0300126 mdev->regs = devm_ioremap_resource(&pdev->dev, res);
127 if (IS_ERR(mdev->regs))
128 return PTR_ERR(mdev->regs);
Sascha Hauera5fd9132009-01-07 18:08:58 -0800129
Alexander Shiyan001d1952013-11-29 15:39:30 +0400130 err = clk_prepare_enable(mdev->clk);
131 if (err)
132 return err;
133
Alexander Shiyanfc945d62014-02-22 11:29:51 +0400134 writeb(clkdiv - 1, mdev->regs + MXC_W1_TIME_DIVIDER);
Sascha Hauera5fd9132009-01-07 18:08:58 -0800135
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;
139
Sascha Hauera5fd9132009-01-07 18:08:58 -0800140 platform_set_drvdata(pdev, mdev);
Alexander Shiyan001d1952013-11-29 15:39:30 +0400141
142 err = w1_add_master_device(&mdev->bus_master);
143 if (err)
144 clk_disable_unprepare(mdev->clk);
145
146 return err;
Sascha Hauera5fd9132009-01-07 18:08:58 -0800147}
148
149/*
150 * disassociate the w1 device from the driver
151 */
Bill Pemberton82849a92012-11-19 13:26:23 -0500152static int mxc_w1_remove(struct platform_device *pdev)
Sascha Hauera5fd9132009-01-07 18:08:58 -0800153{
154 struct mxc_w1_device *mdev = platform_get_drvdata(pdev);
Sascha Hauera5fd9132009-01-07 18:08:58 -0800155
156 w1_remove_master_device(&mdev->bus_master);
157
Sascha Hauer60178b62012-03-07 20:59:36 +0100158 clk_disable_unprepare(mdev->clk);
Sascha Hauera5fd9132009-01-07 18:08:58 -0800159
Sascha Hauera5fd9132009-01-07 18:08:58 -0800160 return 0;
161}
162
Martin Fuzzey28c55dc2013-01-29 16:46:10 +0100163static struct of_device_id mxc_w1_dt_ids[] = {
164 { .compatible = "fsl,imx21-owire" },
165 { /* sentinel */ }
166};
167MODULE_DEVICE_TABLE(of, mxc_w1_dt_ids);
168
Sascha Hauera5fd9132009-01-07 18:08:58 -0800169static struct platform_driver mxc_w1_driver = {
170 .driver = {
Martin Fuzzey28c55dc2013-01-29 16:46:10 +0100171 .name = "mxc_w1",
Alexander Shiyan18fd9e3592014-02-22 11:29:50 +0400172 .owner = THIS_MODULE,
Martin Fuzzey28c55dc2013-01-29 16:46:10 +0100173 .of_match_table = mxc_w1_dt_ids,
Sascha Hauera5fd9132009-01-07 18:08:58 -0800174 },
175 .probe = mxc_w1_probe,
Greg Kroah-Hartman10532fe2012-12-21 12:55:26 -0800176 .remove = mxc_w1_remove,
Sascha Hauera5fd9132009-01-07 18:08:58 -0800177};
Fabio Estevamfd21bfc2012-11-19 10:19:48 -0200178module_platform_driver(mxc_w1_driver);
Sascha Hauera5fd9132009-01-07 18:08:58 -0800179
180MODULE_LICENSE("GPL");
181MODULE_AUTHOR("Freescale Semiconductors Inc");
182MODULE_DESCRIPTION("Driver for One-Wire on MXC");