brintos

brintos / linux-shallow public Read only

0
0
Text · 2.7 KiB · 7bb7876 Raw
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