linux/drivers/w1/masters/mxc_w1.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Copyright 2005-2008 Freescale Semiconductor, Inc. All Rights Reserved.
   4 * Copyright 2008 Luotao Fu, kernel@pengutronix.de
   5 */
   6
   7#include <linux/clk.h>
   8#include <linux/delay.h>
   9#include <linux/io.h>
  10#include <linux/jiffies.h>
  11#include <linux/module.h>
  12#include <linux/mod_devicetable.h>
  13#include <linux/platform_device.h>
  14
  15#include <linux/w1.h>
  16
  17/*
  18 * MXC W1 Register offsets
  19 */
  20#define MXC_W1_CONTROL          0x00
  21# define MXC_W1_CONTROL_RDST    BIT(3)
  22# define MXC_W1_CONTROL_WR(x)   BIT(5 - (x))
  23# define MXC_W1_CONTROL_PST     BIT(6)
  24# define MXC_W1_CONTROL_RPP     BIT(7)
  25#define MXC_W1_TIME_DIVIDER     0x02
  26#define MXC_W1_RESET            0x04
  27# define MXC_W1_RESET_RST       BIT(0)
  28
  29struct mxc_w1_device {
  30        void __iomem *regs;
  31        struct clk *clk;
  32        struct w1_bus_master bus_master;
  33};
  34
  35/*
  36 * this is the low level routine to
  37 * reset the device on the One Wire interface
  38 * on the hardware
  39 */
  40static u8 mxc_w1_ds2_reset_bus(void *data)
  41{
  42        struct mxc_w1_device *dev = data;
  43        unsigned long timeout;
  44
  45        writeb(MXC_W1_CONTROL_RPP, dev->regs + MXC_W1_CONTROL);
  46
  47        /* Wait for reset sequence 511+512us, use 1500us for sure */
  48        timeout = jiffies + usecs_to_jiffies(1500);
  49
  50        udelay(511 + 512);
  51
  52        do {
  53                u8 ctrl = readb(dev->regs + MXC_W1_CONTROL);
  54
  55                /* PST bit is valid after the RPP bit is self-cleared */
  56                if (!(ctrl & MXC_W1_CONTROL_RPP))
  57                        return !(ctrl & MXC_W1_CONTROL_PST);
  58        } while (time_is_after_jiffies(timeout));
  59
  60        return 1;
  61}
  62
  63/*
  64 * this is the low level routine to read/write a bit on the One Wire
  65 * interface on the hardware. It does write 0 if parameter bit is set
  66 * to 0, otherwise a write 1/read.
  67 */
  68static u8 mxc_w1_ds2_touch_bit(void *data, u8 bit)
  69{
  70        struct mxc_w1_device *dev = data;
  71        unsigned long timeout;
  72
  73        writeb(MXC_W1_CONTROL_WR(bit), dev->regs + MXC_W1_CONTROL);
  74
  75        /* Wait for read/write bit (60us, Max 120us), use 200us for sure */
  76        timeout = jiffies + usecs_to_jiffies(200);
  77
  78        udelay(60);
  79
  80        do {
  81                u8 ctrl = readb(dev->regs + MXC_W1_CONTROL);
  82
  83                /* RDST bit is valid after the WR1/RD bit is self-cleared */
  84                if (!(ctrl & MXC_W1_CONTROL_WR(bit)))
  85                        return !!(ctrl & MXC_W1_CONTROL_RDST);
  86        } while (time_is_after_jiffies(timeout));
  87
  88        return 0;
  89}
  90
  91static int mxc_w1_probe(struct platform_device *pdev)
  92{
  93        struct mxc_w1_device *mdev;
  94        unsigned long clkrate;
  95        unsigned int clkdiv;
  96        int err;
  97
  98        mdev = devm_kzalloc(&pdev->dev, sizeof(struct mxc_w1_device),
  99                            GFP_KERNEL);
 100        if (!mdev)
 101                return -ENOMEM;
 102
 103        mdev->clk = devm_clk_get(&pdev->dev, NULL);
 104        if (IS_ERR(mdev->clk))
 105                return PTR_ERR(mdev->clk);
 106
 107        err = clk_prepare_enable(mdev->clk);
 108        if (err)
 109                return err;
 110
 111        clkrate = clk_get_rate(mdev->clk);
 112        if (clkrate < 10000000)
 113                dev_warn(&pdev->dev,
 114                         "Low clock frequency causes improper function\n");
 115
 116        clkdiv = DIV_ROUND_CLOSEST(clkrate, 1000000);
 117        clkrate /= clkdiv;
 118        if ((clkrate < 980000) || (clkrate > 1020000))
 119                dev_warn(&pdev->dev,
 120                         "Incorrect time base frequency %lu Hz\n", clkrate);
 121
 122        mdev->regs = devm_platform_ioremap_resource(pdev, 0);
 123        if (IS_ERR(mdev->regs)) {
 124                err = PTR_ERR(mdev->regs);
 125                goto out_disable_clk;
 126        }
 127
 128        /* Software reset 1-Wire module */
 129        writeb(MXC_W1_RESET_RST, mdev->regs + MXC_W1_RESET);
 130        writeb(0, mdev->regs + MXC_W1_RESET);
 131
 132        writeb(clkdiv - 1, mdev->regs + MXC_W1_TIME_DIVIDER);
 133
 134        mdev->bus_master.data = mdev;
 135        mdev->bus_master.reset_bus = mxc_w1_ds2_reset_bus;
 136        mdev->bus_master.touch_bit = mxc_w1_ds2_touch_bit;
 137
 138        platform_set_drvdata(pdev, mdev);
 139
 140        err = w1_add_master_device(&mdev->bus_master);
 141        if (err)
 142                goto out_disable_clk;
 143
 144        return 0;
 145
 146out_disable_clk:
 147        clk_disable_unprepare(mdev->clk);
 148        return err;
 149}
 150
 151/*
 152 * disassociate the w1 device from the driver
 153 */
 154static int mxc_w1_remove(struct platform_device *pdev)
 155{
 156        struct mxc_w1_device *mdev = platform_get_drvdata(pdev);
 157
 158        w1_remove_master_device(&mdev->bus_master);
 159
 160        clk_disable_unprepare(mdev->clk);
 161
 162        return 0;
 163}
 164
 165static const struct of_device_id mxc_w1_dt_ids[] = {
 166        { .compatible = "fsl,imx21-owire" },
 167        { /* sentinel */ }
 168};
 169MODULE_DEVICE_TABLE(of, mxc_w1_dt_ids);
 170
 171static struct platform_driver mxc_w1_driver = {
 172        .driver = {
 173                .name = "mxc_w1",
 174                .of_match_table = mxc_w1_dt_ids,
 175        },
 176        .probe = mxc_w1_probe,
 177        .remove = mxc_w1_remove,
 178};
 179module_platform_driver(mxc_w1_driver);
 180
 181MODULE_LICENSE("GPL");
 182MODULE_AUTHOR("Freescale Semiconductors Inc");
 183MODULE_DESCRIPTION("Driver for One-Wire on MXC");
 184