1/* 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. 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 * MXC W1 Register offsets 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 * this is the low level routine to 45 * reset the device on the One Wire interface 46 * on the hardware 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 /* Wait for reset sequence 511+512us, use 1500us for sure */ 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 /* PST bit is valid after the RPP bit is self-cleared */ 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 * this is the low level routine to read/write a bit on the One Wire 73 * interface on the hardware. It does write 0 if parameter bit is set 74 * to 0, otherwise a write 1/read. 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 /* Wait for read/write bit (60us, Max 120us), use 200us for sure */ 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 /* RDST bit is valid after the WR1/RD bit is self-cleared */ 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 /* Software reset 1-Wire module */ 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 * disassociate the w1 device from the driver 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 { /* sentinel */ } 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