xref: /openbmc/linux/drivers/i2c/busses/i2c-simtec.c (revision e190a0c3)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) 2005 Simtec Electronics
4  *	Ben Dooks <ben@simtec.co.uk>
5  *
6  * Simtec Generic I2C Controller
7 */
8 
9 #include <linux/kernel.h>
10 #include <linux/module.h>
11 #include <linux/delay.h>
12 #include <linux/platform_device.h>
13 #include <linux/slab.h>
14 #include <linux/io.h>
15 
16 #include <linux/i2c.h>
17 #include <linux/i2c-algo-bit.h>
18 
19 struct simtec_i2c_data {
20 	struct resource		*ioarea;
21 	void __iomem		*reg;
22 	struct i2c_adapter	 adap;
23 	struct i2c_algo_bit_data bit;
24 };
25 
26 #define CMD_SET_SDA	(1<<2)
27 #define CMD_SET_SCL	(1<<3)
28 
29 #define STATE_SDA	(1<<0)
30 #define STATE_SCL	(1<<1)
31 
32 /* i2c bit-bus functions */
33 
simtec_i2c_setsda(void * pw,int state)34 static void simtec_i2c_setsda(void *pw, int state)
35 {
36 	struct simtec_i2c_data *pd = pw;
37 	writeb(CMD_SET_SDA | (state ? STATE_SDA : 0), pd->reg);
38 }
39 
simtec_i2c_setscl(void * pw,int state)40 static void simtec_i2c_setscl(void *pw, int state)
41 {
42 	struct simtec_i2c_data *pd = pw;
43 	writeb(CMD_SET_SCL | (state ? STATE_SCL : 0), pd->reg);
44 }
45 
simtec_i2c_getsda(void * pw)46 static int simtec_i2c_getsda(void *pw)
47 {
48 	struct simtec_i2c_data *pd = pw;
49 	return readb(pd->reg) & STATE_SDA ? 1 : 0;
50 }
51 
simtec_i2c_getscl(void * pw)52 static int simtec_i2c_getscl(void *pw)
53 {
54 	struct simtec_i2c_data *pd = pw;
55 	return readb(pd->reg) & STATE_SCL ? 1 : 0;
56 }
57 
58 /* device registration */
59 
simtec_i2c_probe(struct platform_device * dev)60 static int simtec_i2c_probe(struct platform_device *dev)
61 {
62 	struct simtec_i2c_data *pd;
63 	struct resource *res;
64 	int size;
65 	int ret;
66 
67 	pd = kzalloc(sizeof(struct simtec_i2c_data), GFP_KERNEL);
68 	if (pd == NULL)
69 		return -ENOMEM;
70 
71 	platform_set_drvdata(dev, pd);
72 
73 	res = platform_get_resource(dev, IORESOURCE_MEM, 0);
74 	if (res == NULL) {
75 		dev_err(&dev->dev, "cannot find IO resource\n");
76 		ret = -ENOENT;
77 		goto err;
78 	}
79 
80 	size = resource_size(res);
81 
82 	pd->ioarea = request_mem_region(res->start, size, dev->name);
83 	if (pd->ioarea == NULL) {
84 		dev_err(&dev->dev, "cannot request IO\n");
85 		ret = -ENXIO;
86 		goto err;
87 	}
88 
89 	pd->reg = ioremap(res->start, size);
90 	if (pd->reg == NULL) {
91 		dev_err(&dev->dev, "cannot map IO\n");
92 		ret = -ENXIO;
93 		goto err_res;
94 	}
95 
96 	/* setup the private data */
97 
98 	pd->adap.owner = THIS_MODULE;
99 	pd->adap.algo_data = &pd->bit;
100 	pd->adap.dev.parent = &dev->dev;
101 
102 	strscpy(pd->adap.name, "Simtec I2C", sizeof(pd->adap.name));
103 
104 	pd->bit.data = pd;
105 	pd->bit.setsda = simtec_i2c_setsda;
106 	pd->bit.setscl = simtec_i2c_setscl;
107 	pd->bit.getsda = simtec_i2c_getsda;
108 	pd->bit.getscl = simtec_i2c_getscl;
109 	pd->bit.timeout = HZ;
110 	pd->bit.udelay = 20;
111 
112 	ret = i2c_bit_add_bus(&pd->adap);
113 	if (ret)
114 		goto err_all;
115 
116 	return 0;
117 
118  err_all:
119 	iounmap(pd->reg);
120 
121  err_res:
122 	release_mem_region(pd->ioarea->start, size);
123 
124  err:
125 	kfree(pd);
126 	return ret;
127 }
128 
simtec_i2c_remove(struct platform_device * dev)129 static void simtec_i2c_remove(struct platform_device *dev)
130 {
131 	struct simtec_i2c_data *pd = platform_get_drvdata(dev);
132 
133 	i2c_del_adapter(&pd->adap);
134 
135 	iounmap(pd->reg);
136 	release_mem_region(pd->ioarea->start, resource_size(pd->ioarea));
137 	kfree(pd);
138 }
139 
140 /* device driver */
141 
142 static struct platform_driver simtec_i2c_driver = {
143 	.driver		= {
144 		.name		= "simtec-i2c",
145 	},
146 	.probe		= simtec_i2c_probe,
147 	.remove_new	= simtec_i2c_remove,
148 };
149 
150 module_platform_driver(simtec_i2c_driver);
151 
152 MODULE_DESCRIPTION("Simtec Generic I2C Bus driver");
153 MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
154 MODULE_LICENSE("GPL");
155 MODULE_ALIAS("platform:simtec-i2c");
156