1/*
2 * Copyright (C) 2007-2010 ST-Ericsson
3 * License terms: GNU General Public License (GPL) version 2
4 * Register access functions for the ABX500 Mixed Signal IC family.
5 * Author: Mattias Wallin <mattias.wallin@stericsson.com>
6 */
7
8#include <linux/list.h>
9#include <linux/slab.h>
10#include <linux/err.h>
11#include <linux/module.h>
12#include <linux/mfd/abx500.h>
13
14static LIST_HEAD(abx500_list);
15
16struct abx500_device_entry {
17	struct list_head list;
18	struct abx500_ops ops;
19	struct device *dev;
20};
21
22static void lookup_ops(struct device *dev, struct abx500_ops **ops)
23{
24	struct abx500_device_entry *dev_entry;
25
26	*ops = NULL;
27	list_for_each_entry(dev_entry, &abx500_list, list) {
28		if (dev_entry->dev == dev) {
29			*ops = &dev_entry->ops;
30			return;
31		}
32	}
33}
34
35int abx500_register_ops(struct device *dev, struct abx500_ops *ops)
36{
37	struct abx500_device_entry *dev_entry;
38
39	dev_entry = devm_kzalloc(dev,
40				 sizeof(struct abx500_device_entry),
41				 GFP_KERNEL);
42	if (!dev_entry) {
43		dev_err(dev, "register_ops kzalloc failed");
44		return -ENOMEM;
45	}
46	dev_entry->dev = dev;
47	memcpy(&dev_entry->ops, ops, sizeof(struct abx500_ops));
48
49	list_add_tail(&dev_entry->list, &abx500_list);
50	return 0;
51}
52EXPORT_SYMBOL(abx500_register_ops);
53
54void abx500_remove_ops(struct device *dev)
55{
56	struct abx500_device_entry *dev_entry, *tmp;
57
58	list_for_each_entry_safe(dev_entry, tmp, &abx500_list, list)
59		if (dev_entry->dev == dev)
60			list_del(&dev_entry->list);
61}
62EXPORT_SYMBOL(abx500_remove_ops);
63
64int abx500_set_register_interruptible(struct device *dev, u8 bank, u8 reg,
65	u8 value)
66{
67	struct abx500_ops *ops;
68
69	lookup_ops(dev->parent, &ops);
70	if ((ops != NULL) && (ops->set_register != NULL))
71		return ops->set_register(dev, bank, reg, value);
72	else
73		return -ENOTSUPP;
74}
75EXPORT_SYMBOL(abx500_set_register_interruptible);
76
77int abx500_get_register_interruptible(struct device *dev, u8 bank, u8 reg,
78	u8 *value)
79{
80	struct abx500_ops *ops;
81
82	lookup_ops(dev->parent, &ops);
83	if ((ops != NULL) && (ops->get_register != NULL))
84		return ops->get_register(dev, bank, reg, value);
85	else
86		return -ENOTSUPP;
87}
88EXPORT_SYMBOL(abx500_get_register_interruptible);
89
90int abx500_get_register_page_interruptible(struct device *dev, u8 bank,
91	u8 first_reg, u8 *regvals, u8 numregs)
92{
93	struct abx500_ops *ops;
94
95	lookup_ops(dev->parent, &ops);
96	if ((ops != NULL) && (ops->get_register_page != NULL))
97		return ops->get_register_page(dev, bank,
98			first_reg, regvals, numregs);
99	else
100		return -ENOTSUPP;
101}
102EXPORT_SYMBOL(abx500_get_register_page_interruptible);
103
104int abx500_mask_and_set_register_interruptible(struct device *dev, u8 bank,
105	u8 reg, u8 bitmask, u8 bitvalues)
106{
107	struct abx500_ops *ops;
108
109	lookup_ops(dev->parent, &ops);
110	if ((ops != NULL) && (ops->mask_and_set_register != NULL))
111		return ops->mask_and_set_register(dev, bank,
112			reg, bitmask, bitvalues);
113	else
114		return -ENOTSUPP;
115}
116EXPORT_SYMBOL(abx500_mask_and_set_register_interruptible);
117
118int abx500_get_chip_id(struct device *dev)
119{
120	struct abx500_ops *ops;
121
122	lookup_ops(dev->parent, &ops);
123	if ((ops != NULL) && (ops->get_chip_id != NULL))
124		return ops->get_chip_id(dev);
125	else
126		return -ENOTSUPP;
127}
128EXPORT_SYMBOL(abx500_get_chip_id);
129
130int abx500_event_registers_startup_state_get(struct device *dev, u8 *event)
131{
132	struct abx500_ops *ops;
133
134	lookup_ops(dev->parent, &ops);
135	if ((ops != NULL) && (ops->event_registers_startup_state_get != NULL))
136		return ops->event_registers_startup_state_get(dev, event);
137	else
138		return -ENOTSUPP;
139}
140EXPORT_SYMBOL(abx500_event_registers_startup_state_get);
141
142int abx500_startup_irq_enabled(struct device *dev, unsigned int irq)
143{
144	struct abx500_ops *ops;
145
146	lookup_ops(dev->parent, &ops);
147	if ((ops != NULL) && (ops->startup_irq_enabled != NULL))
148		return ops->startup_irq_enabled(dev, irq);
149	else
150		return -ENOTSUPP;
151}
152EXPORT_SYMBOL(abx500_startup_irq_enabled);
153
154MODULE_AUTHOR("Mattias Wallin <mattias.wallin@stericsson.com>");
155MODULE_DESCRIPTION("ABX500 core driver");
156MODULE_LICENSE("GPL");
157