Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * sgi_w1.c - w1 master driver for one wire support in SGI ASICs
0004  */
0005 
0006 #include <linux/clk.h>
0007 #include <linux/delay.h>
0008 #include <linux/io.h>
0009 #include <linux/jiffies.h>
0010 #include <linux/module.h>
0011 #include <linux/mod_devicetable.h>
0012 #include <linux/platform_device.h>
0013 #include <linux/platform_data/sgi-w1.h>
0014 
0015 #include <linux/w1.h>
0016 
0017 #define MCR_RD_DATA BIT(0)
0018 #define MCR_DONE    BIT(1)
0019 
0020 #define MCR_PACK(pulse, sample) (((pulse) << 10) | ((sample) << 2))
0021 
0022 struct sgi_w1_device {
0023     u32 __iomem *mcr;
0024     struct w1_bus_master bus_master;
0025     char dev_id[64];
0026 };
0027 
0028 static u8 sgi_w1_wait(u32 __iomem *mcr)
0029 {
0030     u32 mcr_val;
0031 
0032     do {
0033         mcr_val = readl(mcr);
0034     } while (!(mcr_val & MCR_DONE));
0035 
0036     return (mcr_val & MCR_RD_DATA) ? 1 : 0;
0037 }
0038 
0039 /*
0040  * this is the low level routine to
0041  * reset the device on the One Wire interface
0042  * on the hardware
0043  */
0044 static u8 sgi_w1_reset_bus(void *data)
0045 {
0046     struct sgi_w1_device *dev = data;
0047     u8 ret;
0048 
0049     writel(MCR_PACK(520, 65), dev->mcr);
0050     ret = sgi_w1_wait(dev->mcr);
0051     udelay(500); /* recovery time */
0052     return ret;
0053 }
0054 
0055 /*
0056  * this is the low level routine to read/write a bit on the One Wire
0057  * interface on the hardware. It does write 0 if parameter bit is set
0058  * to 0, otherwise a write 1/read.
0059  */
0060 static u8 sgi_w1_touch_bit(void *data, u8 bit)
0061 {
0062     struct sgi_w1_device *dev = data;
0063     u8 ret;
0064 
0065     if (bit)
0066         writel(MCR_PACK(6, 13), dev->mcr);
0067     else
0068         writel(MCR_PACK(80, 30), dev->mcr);
0069 
0070     ret = sgi_w1_wait(dev->mcr);
0071     if (bit)
0072         udelay(100); /* recovery */
0073     return ret;
0074 }
0075 
0076 static int sgi_w1_probe(struct platform_device *pdev)
0077 {
0078     struct sgi_w1_device *sdev;
0079     struct sgi_w1_platform_data *pdata;
0080 
0081     sdev = devm_kzalloc(&pdev->dev, sizeof(struct sgi_w1_device),
0082                 GFP_KERNEL);
0083     if (!sdev)
0084         return -ENOMEM;
0085 
0086     sdev->mcr = devm_platform_ioremap_resource(pdev, 0);
0087     if (IS_ERR(sdev->mcr))
0088         return PTR_ERR(sdev->mcr);
0089 
0090     sdev->bus_master.data = sdev;
0091     sdev->bus_master.reset_bus = sgi_w1_reset_bus;
0092     sdev->bus_master.touch_bit = sgi_w1_touch_bit;
0093 
0094     pdata = dev_get_platdata(&pdev->dev);
0095     if (pdata) {
0096         strlcpy(sdev->dev_id, pdata->dev_id, sizeof(sdev->dev_id));
0097         sdev->bus_master.dev_id = sdev->dev_id;
0098     }
0099 
0100     platform_set_drvdata(pdev, sdev);
0101 
0102     return w1_add_master_device(&sdev->bus_master);
0103 }
0104 
0105 /*
0106  * disassociate the w1 device from the driver
0107  */
0108 static int sgi_w1_remove(struct platform_device *pdev)
0109 {
0110     struct sgi_w1_device *sdev = platform_get_drvdata(pdev);
0111 
0112     w1_remove_master_device(&sdev->bus_master);
0113 
0114     return 0;
0115 }
0116 
0117 static struct platform_driver sgi_w1_driver = {
0118     .driver = {
0119         .name = "sgi_w1",
0120     },
0121     .probe = sgi_w1_probe,
0122     .remove = sgi_w1_remove,
0123 };
0124 module_platform_driver(sgi_w1_driver);
0125 
0126 MODULE_LICENSE("GPL");
0127 MODULE_AUTHOR("Thomas Bogendoerfer");
0128 MODULE_DESCRIPTION("Driver for One-Wire IP in SGI ASICs");