Linux Audio

Check our new training course

Loading...
  1/*
  2 *  i2c-versatile.c
  3 *
  4 *  Copyright (C) 2006 ARM Ltd.
  5 *  written by Russell King, Deep Blue Solutions Ltd.
  6 *
  7 * This program is free software; you can redistribute it and/or modify
  8 * it under the terms of the GNU General Public License version 2 as
  9 * published by the Free Software Foundation.
 10 */
 11#include <linux/kernel.h>
 12#include <linux/module.h>
 13#include <linux/i2c.h>
 14#include <linux/i2c-algo-bit.h>
 15#include <linux/init.h>
 16#include <linux/platform_device.h>
 17#include <linux/slab.h>
 18#include <linux/io.h>
 19#include <linux/of_i2c.h>
 20
 21#define I2C_CONTROL	0x00
 22#define I2C_CONTROLS	0x00
 23#define I2C_CONTROLC	0x04
 24#define SCL		(1 << 0)
 25#define SDA		(1 << 1)
 26
 27struct i2c_versatile {
 28	struct i2c_adapter	 adap;
 29	struct i2c_algo_bit_data algo;
 30	void __iomem		 *base;
 31};
 32
 33static void i2c_versatile_setsda(void *data, int state)
 34{
 35	struct i2c_versatile *i2c = data;
 36
 37	writel(SDA, i2c->base + (state ? I2C_CONTROLS : I2C_CONTROLC));
 38}
 39
 40static void i2c_versatile_setscl(void *data, int state)
 41{
 42	struct i2c_versatile *i2c = data;
 43
 44	writel(SCL, i2c->base + (state ? I2C_CONTROLS : I2C_CONTROLC));
 45}
 46
 47static int i2c_versatile_getsda(void *data)
 48{
 49	struct i2c_versatile *i2c = data;
 50	return !!(readl(i2c->base + I2C_CONTROL) & SDA);
 51}
 52
 53static int i2c_versatile_getscl(void *data)
 54{
 55	struct i2c_versatile *i2c = data;
 56	return !!(readl(i2c->base + I2C_CONTROL) & SCL);
 57}
 58
 59static struct i2c_algo_bit_data i2c_versatile_algo = {
 60	.setsda	= i2c_versatile_setsda,
 61	.setscl = i2c_versatile_setscl,
 62	.getsda	= i2c_versatile_getsda,
 63	.getscl = i2c_versatile_getscl,
 64	.udelay	= 30,
 65	.timeout = HZ,
 66};
 67
 68static int i2c_versatile_probe(struct platform_device *dev)
 69{
 70	struct i2c_versatile *i2c;
 71	struct resource *r;
 72	int ret;
 73
 74	r = platform_get_resource(dev, IORESOURCE_MEM, 0);
 75	if (!r) {
 76		ret = -EINVAL;
 77		goto err_out;
 78	}
 79
 80	if (!request_mem_region(r->start, resource_size(r), "versatile-i2c")) {
 81		ret = -EBUSY;
 82		goto err_out;
 83	}
 84
 85	i2c = kzalloc(sizeof(struct i2c_versatile), GFP_KERNEL);
 86	if (!i2c) {
 87		ret = -ENOMEM;
 88		goto err_release;
 89	}
 90
 91	i2c->base = ioremap(r->start, resource_size(r));
 92	if (!i2c->base) {
 93		ret = -ENOMEM;
 94		goto err_free;
 95	}
 96
 97	writel(SCL | SDA, i2c->base + I2C_CONTROLS);
 98
 99	i2c->adap.owner = THIS_MODULE;
100	strlcpy(i2c->adap.name, "Versatile I2C adapter", sizeof(i2c->adap.name));
101	i2c->adap.algo_data = &i2c->algo;
102	i2c->adap.dev.parent = &dev->dev;
103	i2c->adap.dev.of_node = dev->dev.of_node;
104	i2c->algo = i2c_versatile_algo;
105	i2c->algo.data = i2c;
106
107	i2c->adap.nr = dev->id;
108	ret = i2c_bit_add_numbered_bus(&i2c->adap);
109	if (ret >= 0) {
110		platform_set_drvdata(dev, i2c);
111		of_i2c_register_devices(&i2c->adap);
112		return 0;
113	}
114
115	iounmap(i2c->base);
116 err_free:
117	kfree(i2c);
118 err_release:
119	release_mem_region(r->start, resource_size(r));
120 err_out:
121	return ret;
122}
123
124static int i2c_versatile_remove(struct platform_device *dev)
125{
126	struct i2c_versatile *i2c = platform_get_drvdata(dev);
127
128	platform_set_drvdata(dev, NULL);
129
130	i2c_del_adapter(&i2c->adap);
131	return 0;
132}
133
134static const struct of_device_id i2c_versatile_match[] = {
135	{ .compatible = "arm,versatile-i2c", },
136	{},
137};
138MODULE_DEVICE_TABLE(of, i2c_versatile_match);
139
140static struct platform_driver i2c_versatile_driver = {
141	.probe		= i2c_versatile_probe,
142	.remove		= i2c_versatile_remove,
143	.driver		= {
144		.name	= "versatile-i2c",
145		.owner	= THIS_MODULE,
146		.of_match_table = i2c_versatile_match,
147	},
148};
149
150static int __init i2c_versatile_init(void)
151{
152	return platform_driver_register(&i2c_versatile_driver);
153}
154
155static void __exit i2c_versatile_exit(void)
156{
157	platform_driver_unregister(&i2c_versatile_driver);
158}
159
160subsys_initcall(i2c_versatile_init);
161module_exit(i2c_versatile_exit);
162
163MODULE_DESCRIPTION("ARM Versatile I2C bus driver");
164MODULE_LICENSE("GPL");
165MODULE_ALIAS("platform:versatile-i2c");