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 112e5279ff6SJulia Lawall mdev = devm_kzalloc(&pdev->dev, sizeof(struct mxc_w1_device), 113e5279ff6SJulia Lawall GFP_KERNEL); 114a5fd9139SSascha Hauer if (!mdev) 115a5fd9139SSascha Hauer return -ENOMEM; 116a5fd9139SSascha Hauer 117e5279ff6SJulia Lawall mdev->clk = devm_clk_get(&pdev->dev, NULL); 118e5279ff6SJulia Lawall if (IS_ERR(mdev->clk)) 119e5279ff6SJulia Lawall return PTR_ERR(mdev->clk); 120a5fd9139SSascha Hauer 121a5fd9139SSascha Hauer mdev->clkdiv = (clk_get_rate(mdev->clk) / 1000000) - 1; 122a5fd9139SSascha Hauer 123e5279ff6SJulia Lawall res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 124e5279ff6SJulia Lawall mdev->regs = devm_request_and_ioremap(&pdev->dev, res); 125e5279ff6SJulia Lawall if (!mdev->regs) 126e5279ff6SJulia Lawall return -EBUSY; 127a5fd9139SSascha Hauer 12860178b63SSascha Hauer clk_prepare_enable(mdev->clk); 129a5fd9139SSascha Hauer __raw_writeb(mdev->clkdiv, mdev->regs + MXC_W1_TIME_DIVIDER); 130a5fd9139SSascha Hauer 131a5fd9139SSascha Hauer mdev->bus_master.data = mdev; 132a5fd9139SSascha Hauer mdev->bus_master.reset_bus = mxc_w1_ds2_reset_bus; 133a5fd9139SSascha Hauer mdev->bus_master.touch_bit = mxc_w1_ds2_touch_bit; 134a5fd9139SSascha Hauer 135a5fd9139SSascha Hauer err = w1_add_master_device(&mdev->bus_master); 136a5fd9139SSascha Hauer 137a5fd9139SSascha Hauer if (err) 138e5279ff6SJulia Lawall return err; 139a5fd9139SSascha Hauer 140a5fd9139SSascha Hauer platform_set_drvdata(pdev, mdev); 141a5fd9139SSascha Hauer return 0; 142a5fd9139SSascha Hauer } 143a5fd9139SSascha Hauer 144a5fd9139SSascha Hauer /* 145a5fd9139SSascha Hauer * disassociate the w1 device from the driver 146a5fd9139SSascha Hauer */ 14782849a93SBill Pemberton static int mxc_w1_remove(struct platform_device *pdev) 148a5fd9139SSascha Hauer { 149a5fd9139SSascha Hauer struct mxc_w1_device *mdev = platform_get_drvdata(pdev); 150a5fd9139SSascha Hauer 151a5fd9139SSascha Hauer w1_remove_master_device(&mdev->bus_master); 152a5fd9139SSascha Hauer 15360178b63SSascha Hauer clk_disable_unprepare(mdev->clk); 154a5fd9139SSascha Hauer 155a5fd9139SSascha Hauer platform_set_drvdata(pdev, NULL); 156a5fd9139SSascha Hauer 157a5fd9139SSascha Hauer return 0; 158a5fd9139SSascha Hauer } 159a5fd9139SSascha Hauer 160a5fd9139SSascha Hauer static struct platform_driver mxc_w1_driver = { 161a5fd9139SSascha Hauer .driver = { 162a5fd9139SSascha Hauer .name = "mxc_w1", 163a5fd9139SSascha Hauer }, 164a5fd9139SSascha Hauer .probe = mxc_w1_probe, 16510532fe7SGreg Kroah-Hartman .remove = mxc_w1_remove, 166a5fd9139SSascha Hauer }; 167fd21bfccSFabio Estevam module_platform_driver(mxc_w1_driver); 168a5fd9139SSascha Hauer 169a5fd9139SSascha Hauer MODULE_LICENSE("GPL"); 170a5fd9139SSascha Hauer MODULE_AUTHOR("Freescale Semiconductors Inc"); 171a5fd9139SSascha Hauer MODULE_DESCRIPTION("Driver for One-Wire on MXC"); 172