0001
0002
0003
0004
0005
0006
0007 #include <linux/clk.h>
0008 #include <linux/delay.h>
0009 #include <linux/io.h>
0010 #include <linux/ktime.h>
0011 #include <linux/module.h>
0012 #include <linux/mod_devicetable.h>
0013 #include <linux/platform_device.h>
0014
0015 #include <linux/w1.h>
0016
0017
0018
0019
0020 #define MXC_W1_CONTROL 0x00
0021 # define MXC_W1_CONTROL_RDST BIT(3)
0022 # define MXC_W1_CONTROL_WR(x) BIT(5 - (x))
0023 # define MXC_W1_CONTROL_PST BIT(6)
0024 # define MXC_W1_CONTROL_RPP BIT(7)
0025 #define MXC_W1_TIME_DIVIDER 0x02
0026 #define MXC_W1_RESET 0x04
0027 # define MXC_W1_RESET_RST BIT(0)
0028
0029 struct mxc_w1_device {
0030 void __iomem *regs;
0031 struct clk *clk;
0032 struct w1_bus_master bus_master;
0033 };
0034
0035
0036
0037
0038
0039
0040 static u8 mxc_w1_ds2_reset_bus(void *data)
0041 {
0042 struct mxc_w1_device *dev = data;
0043 ktime_t timeout;
0044
0045 writeb(MXC_W1_CONTROL_RPP, dev->regs + MXC_W1_CONTROL);
0046
0047
0048 timeout = ktime_add_us(ktime_get(), 1500);
0049
0050 udelay(511 + 512);
0051
0052 do {
0053 u8 ctrl = readb(dev->regs + MXC_W1_CONTROL);
0054
0055
0056 if (!(ctrl & MXC_W1_CONTROL_RPP))
0057 return !(ctrl & MXC_W1_CONTROL_PST);
0058 } while (ktime_before(ktime_get(), timeout));
0059
0060 return 1;
0061 }
0062
0063
0064
0065
0066
0067
0068 static u8 mxc_w1_ds2_touch_bit(void *data, u8 bit)
0069 {
0070 struct mxc_w1_device *dev = data;
0071 ktime_t timeout;
0072
0073 writeb(MXC_W1_CONTROL_WR(bit), dev->regs + MXC_W1_CONTROL);
0074
0075
0076 timeout = ktime_add_us(ktime_get(), 200);
0077
0078 udelay(60);
0079
0080 do {
0081 u8 ctrl = readb(dev->regs + MXC_W1_CONTROL);
0082
0083
0084 if (!(ctrl & MXC_W1_CONTROL_WR(bit)))
0085 return !!(ctrl & MXC_W1_CONTROL_RDST);
0086 } while (ktime_before(ktime_get(), timeout));
0087
0088 return 0;
0089 }
0090
0091 static int mxc_w1_probe(struct platform_device *pdev)
0092 {
0093 struct mxc_w1_device *mdev;
0094 unsigned long clkrate;
0095 unsigned int clkdiv;
0096 int err;
0097
0098 mdev = devm_kzalloc(&pdev->dev, sizeof(struct mxc_w1_device),
0099 GFP_KERNEL);
0100 if (!mdev)
0101 return -ENOMEM;
0102
0103 mdev->clk = devm_clk_get(&pdev->dev, NULL);
0104 if (IS_ERR(mdev->clk))
0105 return PTR_ERR(mdev->clk);
0106
0107 err = clk_prepare_enable(mdev->clk);
0108 if (err)
0109 return err;
0110
0111 clkrate = clk_get_rate(mdev->clk);
0112 if (clkrate < 10000000)
0113 dev_warn(&pdev->dev,
0114 "Low clock frequency causes improper function\n");
0115
0116 clkdiv = DIV_ROUND_CLOSEST(clkrate, 1000000);
0117 clkrate /= clkdiv;
0118 if ((clkrate < 980000) || (clkrate > 1020000))
0119 dev_warn(&pdev->dev,
0120 "Incorrect time base frequency %lu Hz\n", clkrate);
0121
0122 mdev->regs = devm_platform_ioremap_resource(pdev, 0);
0123 if (IS_ERR(mdev->regs)) {
0124 err = PTR_ERR(mdev->regs);
0125 goto out_disable_clk;
0126 }
0127
0128
0129 writeb(MXC_W1_RESET_RST, mdev->regs + MXC_W1_RESET);
0130 writeb(0, mdev->regs + MXC_W1_RESET);
0131
0132 writeb(clkdiv - 1, mdev->regs + MXC_W1_TIME_DIVIDER);
0133
0134 mdev->bus_master.data = mdev;
0135 mdev->bus_master.reset_bus = mxc_w1_ds2_reset_bus;
0136 mdev->bus_master.touch_bit = mxc_w1_ds2_touch_bit;
0137
0138 platform_set_drvdata(pdev, mdev);
0139
0140 err = w1_add_master_device(&mdev->bus_master);
0141 if (err)
0142 goto out_disable_clk;
0143
0144 return 0;
0145
0146 out_disable_clk:
0147 clk_disable_unprepare(mdev->clk);
0148 return err;
0149 }
0150
0151
0152
0153
0154 static int mxc_w1_remove(struct platform_device *pdev)
0155 {
0156 struct mxc_w1_device *mdev = platform_get_drvdata(pdev);
0157
0158 w1_remove_master_device(&mdev->bus_master);
0159
0160 clk_disable_unprepare(mdev->clk);
0161
0162 return 0;
0163 }
0164
0165 static const struct of_device_id mxc_w1_dt_ids[] = {
0166 { .compatible = "fsl,imx21-owire" },
0167 { }
0168 };
0169 MODULE_DEVICE_TABLE(of, mxc_w1_dt_ids);
0170
0171 static struct platform_driver mxc_w1_driver = {
0172 .driver = {
0173 .name = "mxc_w1",
0174 .of_match_table = mxc_w1_dt_ids,
0175 },
0176 .probe = mxc_w1_probe,
0177 .remove = mxc_w1_remove,
0178 };
0179 module_platform_driver(mxc_w1_driver);
0180
0181 MODULE_LICENSE("GPL");
0182 MODULE_AUTHOR("Freescale Semiconductors Inc");
0183 MODULE_DESCRIPTION("Driver for One-Wire on MXC");