1a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer/* 2a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer * Copyright 2005-2008 Freescale Semiconductor, Inc. All Rights Reserved. 3a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer * Copyright 2008 Luotao Fu, kernel@pengutronix.de 4a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer * 5a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer * This program is free software; you can redistribute it and/or 6a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer * modify it under the terms of the GNU General Public License 7a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer * as published by the Free Software Foundation; either version 2 8a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer * of the License, or (at your option) any later version. 9a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer * This program is distributed in the hope that it will be useful, 10a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer * but WITHOUT ANY WARRANTY; without even the implied warranty of 11a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer * GNU General Public License for more details. 13a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer */ 14a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer 15a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer#include <linux/clk.h> 16a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer#include <linux/delay.h> 17a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer#include <linux/io.h> 18b0dceb6a96c2f87a40a9f99bc05711a3f7c1eaa2Alexander Shiyan#include <linux/jiffies.h> 1918fd9e359f2515286ae7c7ac8fd4362675c8eb43Alexander Shiyan#include <linux/module.h> 2018fd9e359f2515286ae7c7ac8fd4362675c8eb43Alexander Shiyan#include <linux/platform_device.h> 21a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer 22a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer#include "../w1.h" 23a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer#include "../w1_int.h" 24a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer 25a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer/* 26a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer * MXC W1 Register offsets 27a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer */ 2818fd9e359f2515286ae7c7ac8fd4362675c8eb43Alexander Shiyan#define MXC_W1_CONTROL 0x00 2918fd9e359f2515286ae7c7ac8fd4362675c8eb43Alexander Shiyan# define MXC_W1_CONTROL_RDST BIT(3) 3018fd9e359f2515286ae7c7ac8fd4362675c8eb43Alexander Shiyan# define MXC_W1_CONTROL_WR(x) BIT(5 - (x)) 3118fd9e359f2515286ae7c7ac8fd4362675c8eb43Alexander Shiyan# define MXC_W1_CONTROL_PST BIT(6) 3218fd9e359f2515286ae7c7ac8fd4362675c8eb43Alexander Shiyan# define MXC_W1_CONTROL_RPP BIT(7) 3318fd9e359f2515286ae7c7ac8fd4362675c8eb43Alexander Shiyan#define MXC_W1_TIME_DIVIDER 0x02 3418fd9e359f2515286ae7c7ac8fd4362675c8eb43Alexander Shiyan#define MXC_W1_RESET 0x04 35b7ce0b5d03f303cba0fff3f9df17f400d4e7a2d8Alexander Shiyan# define MXC_W1_RESET_RST BIT(0) 36a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer 37a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauerstruct mxc_w1_device { 38a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer void __iomem *regs; 39a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer struct clk *clk; 40a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer struct w1_bus_master bus_master; 41a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer}; 42a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer 43a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer/* 44a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer * this is the low level routine to 45a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer * reset the device on the One Wire interface 46a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer * on the hardware 47a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer */ 48a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauerstatic u8 mxc_w1_ds2_reset_bus(void *data) 49a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer{ 50a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer struct mxc_w1_device *dev = data; 51b0dceb6a96c2f87a40a9f99bc05711a3f7c1eaa2Alexander Shiyan unsigned long timeout; 52a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer 53b0dceb6a96c2f87a40a9f99bc05711a3f7c1eaa2Alexander Shiyan writeb(MXC_W1_CONTROL_RPP, dev->regs + MXC_W1_CONTROL); 54a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer 55b0dceb6a96c2f87a40a9f99bc05711a3f7c1eaa2Alexander Shiyan /* Wait for reset sequence 511+512us, use 1500us for sure */ 56b0dceb6a96c2f87a40a9f99bc05711a3f7c1eaa2Alexander Shiyan timeout = jiffies + usecs_to_jiffies(1500); 57a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer 58b0dceb6a96c2f87a40a9f99bc05711a3f7c1eaa2Alexander Shiyan udelay(511 + 512); 59a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer 60b0dceb6a96c2f87a40a9f99bc05711a3f7c1eaa2Alexander Shiyan do { 61b0dceb6a96c2f87a40a9f99bc05711a3f7c1eaa2Alexander Shiyan u8 ctrl = readb(dev->regs + MXC_W1_CONTROL); 62b0dceb6a96c2f87a40a9f99bc05711a3f7c1eaa2Alexander Shiyan 63b0dceb6a96c2f87a40a9f99bc05711a3f7c1eaa2Alexander Shiyan /* PST bit is valid after the RPP bit is self-cleared */ 64b0dceb6a96c2f87a40a9f99bc05711a3f7c1eaa2Alexander Shiyan if (!(ctrl & MXC_W1_CONTROL_RPP)) 65b0dceb6a96c2f87a40a9f99bc05711a3f7c1eaa2Alexander Shiyan return !(ctrl & MXC_W1_CONTROL_PST); 66b0dceb6a96c2f87a40a9f99bc05711a3f7c1eaa2Alexander Shiyan } while (time_is_after_jiffies(timeout)); 67b0dceb6a96c2f87a40a9f99bc05711a3f7c1eaa2Alexander Shiyan 68b0dceb6a96c2f87a40a9f99bc05711a3f7c1eaa2Alexander Shiyan return 1; 69a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer} 70a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer 71a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer/* 72a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer * this is the low level routine to read/write a bit on the One Wire 73a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer * interface on the hardware. It does write 0 if parameter bit is set 74a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer * to 0, otherwise a write 1/read. 75a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer */ 76a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauerstatic u8 mxc_w1_ds2_touch_bit(void *data, u8 bit) 77a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer{ 78f80b2581a7068907076ca92c43866f36f446c039Alexander Shiyan struct mxc_w1_device *dev = data; 79f80b2581a7068907076ca92c43866f36f446c039Alexander Shiyan unsigned long timeout; 80a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer 81f80b2581a7068907076ca92c43866f36f446c039Alexander Shiyan writeb(MXC_W1_CONTROL_WR(bit), dev->regs + MXC_W1_CONTROL); 82a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer 83f80b2581a7068907076ca92c43866f36f446c039Alexander Shiyan /* Wait for read/write bit (60us, Max 120us), use 200us for sure */ 84f80b2581a7068907076ca92c43866f36f446c039Alexander Shiyan timeout = jiffies + usecs_to_jiffies(200); 85a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer 86f80b2581a7068907076ca92c43866f36f446c039Alexander Shiyan udelay(60); 87f80b2581a7068907076ca92c43866f36f446c039Alexander Shiyan 88f80b2581a7068907076ca92c43866f36f446c039Alexander Shiyan do { 89f80b2581a7068907076ca92c43866f36f446c039Alexander Shiyan u8 ctrl = readb(dev->regs + MXC_W1_CONTROL); 90f80b2581a7068907076ca92c43866f36f446c039Alexander Shiyan 91f80b2581a7068907076ca92c43866f36f446c039Alexander Shiyan /* RDST bit is valid after the WR1/RD bit is self-cleared */ 92f80b2581a7068907076ca92c43866f36f446c039Alexander Shiyan if (!(ctrl & MXC_W1_CONTROL_WR(bit))) 93f80b2581a7068907076ca92c43866f36f446c039Alexander Shiyan return !!(ctrl & MXC_W1_CONTROL_RDST); 94f80b2581a7068907076ca92c43866f36f446c039Alexander Shiyan } while (time_is_after_jiffies(timeout)); 95a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer 96f80b2581a7068907076ca92c43866f36f446c039Alexander Shiyan return 0; 97a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer} 98a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer 99479e2bcecdf19ae44940d38248a3e2f9fd8f2c44Bill Pembertonstatic int mxc_w1_probe(struct platform_device *pdev) 100a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer{ 101a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer struct mxc_w1_device *mdev; 10271531f55a83dcb79b89287f6b11fb2e4eb496d4dAlexander Shiyan unsigned long clkrate; 103a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer struct resource *res; 104a0822637258b9e6132de669ac16dfe445c78e932Alexander Shiyan unsigned int clkdiv; 105001d1953eae7089ab148ec32e13848be8d0b3874Alexander Shiyan int err; 106a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer 107e5279ff6c9f5e950feac6e6f48621db912324c07Julia Lawall mdev = devm_kzalloc(&pdev->dev, sizeof(struct mxc_w1_device), 108e5279ff6c9f5e950feac6e6f48621db912324c07Julia Lawall GFP_KERNEL); 109a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer if (!mdev) 110a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer return -ENOMEM; 111a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer 112e5279ff6c9f5e950feac6e6f48621db912324c07Julia Lawall mdev->clk = devm_clk_get(&pdev->dev, NULL); 113e5279ff6c9f5e950feac6e6f48621db912324c07Julia Lawall if (IS_ERR(mdev->clk)) 114e5279ff6c9f5e950feac6e6f48621db912324c07Julia Lawall return PTR_ERR(mdev->clk); 115a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer 11671531f55a83dcb79b89287f6b11fb2e4eb496d4dAlexander Shiyan clkrate = clk_get_rate(mdev->clk); 11771531f55a83dcb79b89287f6b11fb2e4eb496d4dAlexander Shiyan if (clkrate < 10000000) 11871531f55a83dcb79b89287f6b11fb2e4eb496d4dAlexander Shiyan dev_warn(&pdev->dev, 11971531f55a83dcb79b89287f6b11fb2e4eb496d4dAlexander Shiyan "Low clock frequency causes improper function\n"); 12071531f55a83dcb79b89287f6b11fb2e4eb496d4dAlexander Shiyan 12171531f55a83dcb79b89287f6b11fb2e4eb496d4dAlexander Shiyan clkdiv = DIV_ROUND_CLOSEST(clkrate, 1000000); 12271531f55a83dcb79b89287f6b11fb2e4eb496d4dAlexander Shiyan clkrate /= clkdiv; 12371531f55a83dcb79b89287f6b11fb2e4eb496d4dAlexander Shiyan if ((clkrate < 980000) || (clkrate > 1020000)) 12471531f55a83dcb79b89287f6b11fb2e4eb496d4dAlexander Shiyan dev_warn(&pdev->dev, 12571531f55a83dcb79b89287f6b11fb2e4eb496d4dAlexander Shiyan "Incorrect time base frequency %lu Hz\n", clkrate); 126a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer 127e5279ff6c9f5e950feac6e6f48621db912324c07Julia Lawall res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 128388f7bd24d2ffc945ad08be3a592672c1e32156eFabio Estevam mdev->regs = devm_ioremap_resource(&pdev->dev, res); 129388f7bd24d2ffc945ad08be3a592672c1e32156eFabio Estevam if (IS_ERR(mdev->regs)) 130388f7bd24d2ffc945ad08be3a592672c1e32156eFabio Estevam return PTR_ERR(mdev->regs); 131a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer 132001d1953eae7089ab148ec32e13848be8d0b3874Alexander Shiyan err = clk_prepare_enable(mdev->clk); 133001d1953eae7089ab148ec32e13848be8d0b3874Alexander Shiyan if (err) 134001d1953eae7089ab148ec32e13848be8d0b3874Alexander Shiyan return err; 135001d1953eae7089ab148ec32e13848be8d0b3874Alexander Shiyan 136b7ce0b5d03f303cba0fff3f9df17f400d4e7a2d8Alexander Shiyan /* Software reset 1-Wire module */ 137b7ce0b5d03f303cba0fff3f9df17f400d4e7a2d8Alexander Shiyan writeb(MXC_W1_RESET_RST, mdev->regs + MXC_W1_RESET); 138b7ce0b5d03f303cba0fff3f9df17f400d4e7a2d8Alexander Shiyan writeb(0, mdev->regs + MXC_W1_RESET); 139b7ce0b5d03f303cba0fff3f9df17f400d4e7a2d8Alexander Shiyan 140fc945d6eb70ebf29532b94ae309c0d4c6d609c3cAlexander Shiyan writeb(clkdiv - 1, mdev->regs + MXC_W1_TIME_DIVIDER); 141a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer 142a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer mdev->bus_master.data = mdev; 143a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer mdev->bus_master.reset_bus = mxc_w1_ds2_reset_bus; 144a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer mdev->bus_master.touch_bit = mxc_w1_ds2_touch_bit; 145a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer 146001d1953eae7089ab148ec32e13848be8d0b3874Alexander Shiyan platform_set_drvdata(pdev, mdev); 147a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer 148001d1953eae7089ab148ec32e13848be8d0b3874Alexander Shiyan err = w1_add_master_device(&mdev->bus_master); 149a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer if (err) 150001d1953eae7089ab148ec32e13848be8d0b3874Alexander Shiyan clk_disable_unprepare(mdev->clk); 151a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer 152001d1953eae7089ab148ec32e13848be8d0b3874Alexander Shiyan return err; 153a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer} 154a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer 155a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer/* 156a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer * disassociate the w1 device from the driver 157a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer */ 15882849a93aad04c5a438d811081341b245fdade8cBill Pembertonstatic int mxc_w1_remove(struct platform_device *pdev) 159a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer{ 160a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer struct mxc_w1_device *mdev = platform_get_drvdata(pdev); 161a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer 162a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer w1_remove_master_device(&mdev->bus_master); 163a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer 16460178b6329259457013d0e39cbee22aec0230dfbSascha Hauer clk_disable_unprepare(mdev->clk); 165a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer 166a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer return 0; 167a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer} 168a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer 16928c55dc1acc863cb29832b5be2464ebcdafdc3d5Martin Fuzzeystatic struct of_device_id mxc_w1_dt_ids[] = { 17028c55dc1acc863cb29832b5be2464ebcdafdc3d5Martin Fuzzey { .compatible = "fsl,imx21-owire" }, 17128c55dc1acc863cb29832b5be2464ebcdafdc3d5Martin Fuzzey { /* sentinel */ } 17228c55dc1acc863cb29832b5be2464ebcdafdc3d5Martin Fuzzey}; 17328c55dc1acc863cb29832b5be2464ebcdafdc3d5Martin FuzzeyMODULE_DEVICE_TABLE(of, mxc_w1_dt_ids); 17428c55dc1acc863cb29832b5be2464ebcdafdc3d5Martin Fuzzey 175a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauerstatic struct platform_driver mxc_w1_driver = { 176a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer .driver = { 17728c55dc1acc863cb29832b5be2464ebcdafdc3d5Martin Fuzzey .name = "mxc_w1", 17818fd9e359f2515286ae7c7ac8fd4362675c8eb43Alexander Shiyan .owner = THIS_MODULE, 17928c55dc1acc863cb29832b5be2464ebcdafdc3d5Martin Fuzzey .of_match_table = mxc_w1_dt_ids, 180a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer }, 181a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer .probe = mxc_w1_probe, 18210532fe7623dd63ef915be272247ec13f79afbb8Greg Kroah-Hartman .remove = mxc_w1_remove, 183a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer}; 184fd21bfcc2d6e8b7fef20f05deef318b0ab7f8004Fabio Estevammodule_platform_driver(mxc_w1_driver); 185a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha Hauer 186a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha HauerMODULE_LICENSE("GPL"); 187a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha HauerMODULE_AUTHOR("Freescale Semiconductors Inc"); 188a5fd9139f74c722a190b3bd69bbd611a8d91b388Sascha HauerMODULE_DESCRIPTION("Driver for One-Wire on MXC"); 189