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 112a5fd9139SSascha Hauer res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 113a5fd9139SSascha Hauer if (!res) 114a5fd9139SSascha Hauer return -ENODEV; 115a5fd9139SSascha Hauer 116a5fd9139SSascha Hauer mdev = kzalloc(sizeof(struct mxc_w1_device), GFP_KERNEL); 117a5fd9139SSascha Hauer if (!mdev) 118a5fd9139SSascha Hauer return -ENOMEM; 119a5fd9139SSascha Hauer 12099ba2fd2SFabio Estevam mdev->clk = clk_get(&pdev->dev, NULL); 12199ba2fd2SFabio Estevam if (IS_ERR(mdev->clk)) { 12299ba2fd2SFabio Estevam err = PTR_ERR(mdev->clk); 123a5fd9139SSascha Hauer goto failed_clk; 124a5fd9139SSascha Hauer } 125a5fd9139SSascha Hauer 126a5fd9139SSascha Hauer mdev->clkdiv = (clk_get_rate(mdev->clk) / 1000000) - 1; 127a5fd9139SSascha Hauer 128a5fd9139SSascha Hauer res = request_mem_region(res->start, resource_size(res), 129a5fd9139SSascha Hauer "mxc_w1"); 130a5fd9139SSascha Hauer if (!res) { 131a5fd9139SSascha Hauer err = -EBUSY; 132a5fd9139SSascha Hauer goto failed_req; 133a5fd9139SSascha Hauer } 134a5fd9139SSascha Hauer 135a5fd9139SSascha Hauer mdev->regs = ioremap(res->start, resource_size(res)); 136a5fd9139SSascha Hauer if (!mdev->regs) { 137128485daSFabio Estevam dev_err(&pdev->dev, "Cannot map mxc_w1 registers\n"); 138a5fd9139SSascha Hauer goto failed_ioremap; 139a5fd9139SSascha Hauer } 140a5fd9139SSascha Hauer 14160178b63SSascha Hauer clk_prepare_enable(mdev->clk); 142a5fd9139SSascha Hauer __raw_writeb(mdev->clkdiv, mdev->regs + MXC_W1_TIME_DIVIDER); 143a5fd9139SSascha Hauer 144a5fd9139SSascha Hauer mdev->bus_master.data = mdev; 145a5fd9139SSascha Hauer mdev->bus_master.reset_bus = mxc_w1_ds2_reset_bus; 146a5fd9139SSascha Hauer mdev->bus_master.touch_bit = mxc_w1_ds2_touch_bit; 147a5fd9139SSascha Hauer 148a5fd9139SSascha Hauer err = w1_add_master_device(&mdev->bus_master); 149a5fd9139SSascha Hauer 150a5fd9139SSascha Hauer if (err) 151a5fd9139SSascha Hauer goto failed_add; 152a5fd9139SSascha Hauer 153a5fd9139SSascha Hauer platform_set_drvdata(pdev, mdev); 154a5fd9139SSascha Hauer return 0; 155a5fd9139SSascha Hauer 156a5fd9139SSascha Hauer failed_add: 157a5fd9139SSascha Hauer iounmap(mdev->regs); 158a5fd9139SSascha Hauer failed_ioremap: 159a5fd9139SSascha Hauer release_mem_region(res->start, resource_size(res)); 160a5fd9139SSascha Hauer failed_req: 161a5fd9139SSascha Hauer clk_put(mdev->clk); 162a5fd9139SSascha Hauer failed_clk: 163a5fd9139SSascha Hauer kfree(mdev); 164a5fd9139SSascha Hauer return err; 165a5fd9139SSascha Hauer } 166a5fd9139SSascha Hauer 167a5fd9139SSascha Hauer /* 168a5fd9139SSascha Hauer * disassociate the w1 device from the driver 169a5fd9139SSascha Hauer */ 17082849a93SBill Pemberton static int mxc_w1_remove(struct platform_device *pdev) 171a5fd9139SSascha Hauer { 172a5fd9139SSascha Hauer struct mxc_w1_device *mdev = platform_get_drvdata(pdev); 173a5fd9139SSascha Hauer struct resource *res; 174a5fd9139SSascha Hauer 175a5fd9139SSascha Hauer res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 176a5fd9139SSascha Hauer 177a5fd9139SSascha Hauer w1_remove_master_device(&mdev->bus_master); 178a5fd9139SSascha Hauer 179a5fd9139SSascha Hauer iounmap(mdev->regs); 180a5fd9139SSascha Hauer release_mem_region(res->start, resource_size(res)); 18160178b63SSascha Hauer clk_disable_unprepare(mdev->clk); 182a5fd9139SSascha Hauer clk_put(mdev->clk); 183a5fd9139SSascha Hauer 184a5fd9139SSascha Hauer platform_set_drvdata(pdev, NULL); 185a5fd9139SSascha Hauer 186a5fd9139SSascha Hauer return 0; 187a5fd9139SSascha Hauer } 188a5fd9139SSascha Hauer 189a5fd9139SSascha Hauer static struct platform_driver mxc_w1_driver = { 190a5fd9139SSascha Hauer .driver = { 191a5fd9139SSascha Hauer .name = "mxc_w1", 192a5fd9139SSascha Hauer }, 193a5fd9139SSascha Hauer .probe = mxc_w1_probe, 19410532fe7SGreg Kroah-Hartman .remove = mxc_w1_remove, 195a5fd9139SSascha Hauer }; 196fd21bfccSFabio Estevam module_platform_driver(mxc_w1_driver); 197a5fd9139SSascha Hauer 198a5fd9139SSascha Hauer MODULE_LICENSE("GPL"); 199a5fd9139SSascha Hauer MODULE_AUTHOR("Freescale Semiconductors Inc"); 200a5fd9139SSascha Hauer MODULE_DESCRIPTION("Driver for One-Wire on MXC"); 201