174ded38aSThomas Bogendoerfer // SPDX-License-Identifier: GPL-2.0 274ded38aSThomas Bogendoerfer /* 374ded38aSThomas Bogendoerfer * sgi_w1.c - w1 master driver for one wire support in SGI ASICs 474ded38aSThomas Bogendoerfer */ 574ded38aSThomas Bogendoerfer 674ded38aSThomas Bogendoerfer #include <linux/clk.h> 774ded38aSThomas Bogendoerfer #include <linux/delay.h> 874ded38aSThomas Bogendoerfer #include <linux/io.h> 974ded38aSThomas Bogendoerfer #include <linux/jiffies.h> 1074ded38aSThomas Bogendoerfer #include <linux/module.h> 1174ded38aSThomas Bogendoerfer #include <linux/mod_devicetable.h> 1274ded38aSThomas Bogendoerfer #include <linux/platform_device.h> 1374ded38aSThomas Bogendoerfer #include <linux/platform_data/sgi-w1.h> 1474ded38aSThomas Bogendoerfer 1574ded38aSThomas Bogendoerfer #include <linux/w1.h> 1674ded38aSThomas Bogendoerfer 1774ded38aSThomas Bogendoerfer #define MCR_RD_DATA BIT(0) 1874ded38aSThomas Bogendoerfer #define MCR_DONE BIT(1) 1974ded38aSThomas Bogendoerfer 2074ded38aSThomas Bogendoerfer #define MCR_PACK(pulse, sample) (((pulse) << 10) | ((sample) << 2)) 2174ded38aSThomas Bogendoerfer 2274ded38aSThomas Bogendoerfer struct sgi_w1_device { 2374ded38aSThomas Bogendoerfer u32 __iomem *mcr; 2474ded38aSThomas Bogendoerfer struct w1_bus_master bus_master; 2574ded38aSThomas Bogendoerfer char dev_id[64]; 2674ded38aSThomas Bogendoerfer }; 2774ded38aSThomas Bogendoerfer 2874ded38aSThomas Bogendoerfer static u8 sgi_w1_wait(u32 __iomem *mcr) 2974ded38aSThomas Bogendoerfer { 3074ded38aSThomas Bogendoerfer u32 mcr_val; 3174ded38aSThomas Bogendoerfer 3274ded38aSThomas Bogendoerfer do { 3374ded38aSThomas Bogendoerfer mcr_val = readl(mcr); 3474ded38aSThomas Bogendoerfer } while (!(mcr_val & MCR_DONE)); 3574ded38aSThomas Bogendoerfer 3674ded38aSThomas Bogendoerfer return (mcr_val & MCR_RD_DATA) ? 1 : 0; 3774ded38aSThomas Bogendoerfer } 3874ded38aSThomas Bogendoerfer 3974ded38aSThomas Bogendoerfer /* 4074ded38aSThomas Bogendoerfer * this is the low level routine to 4174ded38aSThomas Bogendoerfer * reset the device on the One Wire interface 4274ded38aSThomas Bogendoerfer * on the hardware 4374ded38aSThomas Bogendoerfer */ 4474ded38aSThomas Bogendoerfer static u8 sgi_w1_reset_bus(void *data) 4574ded38aSThomas Bogendoerfer { 4674ded38aSThomas Bogendoerfer struct sgi_w1_device *dev = data; 4774ded38aSThomas Bogendoerfer u8 ret; 4874ded38aSThomas Bogendoerfer 4974ded38aSThomas Bogendoerfer writel(MCR_PACK(520, 65), dev->mcr); 5074ded38aSThomas Bogendoerfer ret = sgi_w1_wait(dev->mcr); 5174ded38aSThomas Bogendoerfer udelay(500); /* recovery time */ 5274ded38aSThomas Bogendoerfer return ret; 5374ded38aSThomas Bogendoerfer } 5474ded38aSThomas Bogendoerfer 5574ded38aSThomas Bogendoerfer /* 5674ded38aSThomas Bogendoerfer * this is the low level routine to read/write a bit on the One Wire 5774ded38aSThomas Bogendoerfer * interface on the hardware. It does write 0 if parameter bit is set 5874ded38aSThomas Bogendoerfer * to 0, otherwise a write 1/read. 5974ded38aSThomas Bogendoerfer */ 6074ded38aSThomas Bogendoerfer static u8 sgi_w1_touch_bit(void *data, u8 bit) 6174ded38aSThomas Bogendoerfer { 6274ded38aSThomas Bogendoerfer struct sgi_w1_device *dev = data; 6374ded38aSThomas Bogendoerfer u8 ret; 6474ded38aSThomas Bogendoerfer 6574ded38aSThomas Bogendoerfer if (bit) 6674ded38aSThomas Bogendoerfer writel(MCR_PACK(6, 13), dev->mcr); 6774ded38aSThomas Bogendoerfer else 6874ded38aSThomas Bogendoerfer writel(MCR_PACK(80, 30), dev->mcr); 6974ded38aSThomas Bogendoerfer 7074ded38aSThomas Bogendoerfer ret = sgi_w1_wait(dev->mcr); 7174ded38aSThomas Bogendoerfer if (bit) 7274ded38aSThomas Bogendoerfer udelay(100); /* recovery */ 7374ded38aSThomas Bogendoerfer return ret; 7474ded38aSThomas Bogendoerfer } 7574ded38aSThomas Bogendoerfer 7674ded38aSThomas Bogendoerfer static int sgi_w1_probe(struct platform_device *pdev) 7774ded38aSThomas Bogendoerfer { 7874ded38aSThomas Bogendoerfer struct sgi_w1_device *sdev; 7974ded38aSThomas Bogendoerfer struct sgi_w1_platform_data *pdata; 8074ded38aSThomas Bogendoerfer 8174ded38aSThomas Bogendoerfer sdev = devm_kzalloc(&pdev->dev, sizeof(struct sgi_w1_device), 8274ded38aSThomas Bogendoerfer GFP_KERNEL); 8374ded38aSThomas Bogendoerfer if (!sdev) 8474ded38aSThomas Bogendoerfer return -ENOMEM; 8574ded38aSThomas Bogendoerfer 86*71200fcbSYueHaibing sdev->mcr = devm_platform_ioremap_resource(pdev, 0); 8774ded38aSThomas Bogendoerfer if (IS_ERR(sdev->mcr)) 8874ded38aSThomas Bogendoerfer return PTR_ERR(sdev->mcr); 8974ded38aSThomas Bogendoerfer 9074ded38aSThomas Bogendoerfer sdev->bus_master.data = sdev; 9174ded38aSThomas Bogendoerfer sdev->bus_master.reset_bus = sgi_w1_reset_bus; 9274ded38aSThomas Bogendoerfer sdev->bus_master.touch_bit = sgi_w1_touch_bit; 9374ded38aSThomas Bogendoerfer 9474ded38aSThomas Bogendoerfer pdata = dev_get_platdata(&pdev->dev); 9574ded38aSThomas Bogendoerfer if (pdata) { 9674ded38aSThomas Bogendoerfer strlcpy(sdev->dev_id, pdata->dev_id, sizeof(sdev->dev_id)); 9774ded38aSThomas Bogendoerfer sdev->bus_master.dev_id = sdev->dev_id; 9874ded38aSThomas Bogendoerfer } 9974ded38aSThomas Bogendoerfer 10074ded38aSThomas Bogendoerfer platform_set_drvdata(pdev, sdev); 10174ded38aSThomas Bogendoerfer 10274ded38aSThomas Bogendoerfer return w1_add_master_device(&sdev->bus_master); 10374ded38aSThomas Bogendoerfer } 10474ded38aSThomas Bogendoerfer 10574ded38aSThomas Bogendoerfer /* 10674ded38aSThomas Bogendoerfer * disassociate the w1 device from the driver 10774ded38aSThomas Bogendoerfer */ 10874ded38aSThomas Bogendoerfer static int sgi_w1_remove(struct platform_device *pdev) 10974ded38aSThomas Bogendoerfer { 11074ded38aSThomas Bogendoerfer struct sgi_w1_device *sdev = platform_get_drvdata(pdev); 11174ded38aSThomas Bogendoerfer 11274ded38aSThomas Bogendoerfer w1_remove_master_device(&sdev->bus_master); 11374ded38aSThomas Bogendoerfer 11474ded38aSThomas Bogendoerfer return 0; 11574ded38aSThomas Bogendoerfer } 11674ded38aSThomas Bogendoerfer 11774ded38aSThomas Bogendoerfer static struct platform_driver sgi_w1_driver = { 11874ded38aSThomas Bogendoerfer .driver = { 11974ded38aSThomas Bogendoerfer .name = "sgi_w1", 12074ded38aSThomas Bogendoerfer }, 12174ded38aSThomas Bogendoerfer .probe = sgi_w1_probe, 12274ded38aSThomas Bogendoerfer .remove = sgi_w1_remove, 12374ded38aSThomas Bogendoerfer }; 12474ded38aSThomas Bogendoerfer module_platform_driver(sgi_w1_driver); 12574ded38aSThomas Bogendoerfer 12674ded38aSThomas Bogendoerfer MODULE_LICENSE("GPL"); 12774ded38aSThomas Bogendoerfer MODULE_AUTHOR("Thomas Bogendoerfer"); 12874ded38aSThomas Bogendoerfer MODULE_DESCRIPTION("Driver for One-Wire IP in SGI ASICs"); 129