127 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * sgi_w1.c - w1 master driver for one wire support in SGI ASICs4 */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 to41 * reset the device on the One Wire interface42 * on the hardware43 */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 Wire57 * interface on the hardware. It does write 0 if parameter bit is set58 * 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 else68 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 strscpy(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 driver107 */108static void 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 115static struct platform_driver sgi_w1_driver = {116 .driver = {117 .name = "sgi_w1",118 },119 .probe = sgi_w1_probe,120 .remove_new = sgi_w1_remove,121};122module_platform_driver(sgi_w1_driver);123 124MODULE_LICENSE("GPL");125MODULE_AUTHOR("Thomas Bogendoerfer");126MODULE_DESCRIPTION("Driver for One-Wire IP in SGI ASICs");127