linux/drivers/w1/masters/sgi_w1.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * sgi_w1.c - w1 master driver for one wire support in SGI ASICs
   4 */
   5
   6#include <linux/clk.h>
   7#include <linux/delay.h>
   8#include <linux/io.h>
   9#include <linux/jiffies.h>
  10#include <linux/module.h>
  11#include <linux/mod_devicetable.h>
  12#include <linux/platform_device.h>
  13#include <linux/platform_data/sgi-w1.h>
  14
  15#include <linux/w1.h>
  16
  17#define MCR_RD_DATA     BIT(0)
  18#define MCR_DONE        BIT(1)
  19
  20#define MCR_PACK(pulse, sample) (((pulse) << 10) | ((sample) << 2))
  21
  22struct sgi_w1_device {
  23        u32 __iomem *mcr;
  24        struct w1_bus_master bus_master;
  25        char dev_id[64];
  26};
  27
  28static u8 sgi_w1_wait(u32 __iomem *mcr)
  29{
  30        u32 mcr_val;
  31
  32        do {
  33                mcr_val = readl(mcr);
  34        } while (!(mcr_val & MCR_DONE));
  35
  36        return (mcr_val & MCR_RD_DATA) ? 1 : 0;
  37}
  38
  39/*
  40 * this is the low level routine to
  41 * reset the device on the One Wire interface
  42 * on the hardware
  43 */
  44static u8 sgi_w1_reset_bus(void *data)
  45{
  46        struct sgi_w1_device *dev = data;
  47        u8 ret;
  48
  49        writel(MCR_PACK(520, 65), dev->mcr);
  50        ret = sgi_w1_wait(dev->mcr);
  51        udelay(500); /* recovery time */
  52        return ret;
  53}
  54
  55/*
  56 * this is the low level routine to read/write a bit on the One Wire
  57 * interface on the hardware. It does write 0 if parameter bit is set
  58 * to 0, otherwise a write 1/read.
  59 */
  60static u8 sgi_w1_touch_bit(void *data, u8 bit)
  61{
  62        struct sgi_w1_device *dev = data;
  63        u8 ret;
  64
  65        if (bit)
  66                writel(MCR_PACK(6, 13), dev->mcr);
  67        else
  68                writel(MCR_PACK(80, 30), dev->mcr);
  69
  70        ret = sgi_w1_wait(dev->mcr);
  71        if (bit)
  72                udelay(100); /* recovery */
  73        return ret;
  74}
  75
  76static int sgi_w1_probe(struct platform_device *pdev)
  77{
  78        struct sgi_w1_device *sdev;
  79        struct sgi_w1_platform_data *pdata;
  80
  81        sdev = devm_kzalloc(&pdev->dev, sizeof(struct sgi_w1_device),
  82                            GFP_KERNEL);
  83        if (!sdev)
  84                return -ENOMEM;
  85
  86        sdev->mcr = devm_platform_ioremap_resource(pdev, 0);
  87        if (IS_ERR(sdev->mcr))
  88                return PTR_ERR(sdev->mcr);
  89
  90        sdev->bus_master.data = sdev;
  91        sdev->bus_master.reset_bus = sgi_w1_reset_bus;
  92        sdev->bus_master.touch_bit = sgi_w1_touch_bit;
  93
  94        pdata = dev_get_platdata(&pdev->dev);
  95        if (pdata) {
  96                strlcpy(sdev->dev_id, pdata->dev_id, sizeof(sdev->dev_id));
  97                sdev->bus_master.dev_id = sdev->dev_id;
  98        }
  99
 100        platform_set_drvdata(pdev, sdev);
 101
 102        return w1_add_master_device(&sdev->bus_master);
 103}
 104
 105/*
 106 * disassociate the w1 device from the driver
 107 */
 108static int sgi_w1_remove(struct platform_device *pdev)
 109{
 110        struct sgi_w1_device *sdev = platform_get_drvdata(pdev);
 111
 112        w1_remove_master_device(&sdev->bus_master);
 113
 114        return 0;
 115}
 116
 117static struct platform_driver sgi_w1_driver = {
 118        .driver = {
 119                .name = "sgi_w1",
 120        },
 121        .probe = sgi_w1_probe,
 122        .remove = sgi_w1_remove,
 123};
 124module_platform_driver(sgi_w1_driver);
 125
 126MODULE_LICENSE("GPL");
 127MODULE_AUTHOR("Thomas Bogendoerfer");
 128MODULE_DESCRIPTION("Driver for One-Wire IP in SGI ASICs");
 129