1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 *  tifm_core.c - TI FlashMedia driver
4 *
5 *  Copyright (C) 2006 Alex Dubov <oakad@yahoo.com>
6 */
7
8#include <linux/tifm.h>
9#include <linux/slab.h>
10#include <linux/init.h>
11#include <linux/idr.h>
12#include <linux/module.h>
13
14#define DRIVER_NAME "tifm_core"
15#define DRIVER_VERSION "0.8"
16
17static struct workqueue_struct *workqueue;
18static DEFINE_IDR(tifm_adapter_idr);
19static DEFINE_SPINLOCK(tifm_adapter_lock);
20
21static const char *tifm_media_type_name(unsigned char type, unsigned char nt)
22{
23	const char *card_type_name[3][3] = {
24		{ "SmartMedia/xD", "MemoryStick", "MMC/SD" },
25		{ "XD", "MS", "SD"},
26		{ "xd", "ms", "sd"}
27	};
28
29	if (nt > 2 || type < 1 || type > 3)
30		return NULL;
31	return card_type_name[nt][type - 1];
32}
33
34static int tifm_dev_match(struct tifm_dev *sock, struct tifm_device_id *id)
35{
36	if (sock->type == id->type)
37		return 1;
38	return 0;
39}
40
41static int tifm_bus_match(struct device *dev, struct device_driver *drv)
42{
43	struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev);
44	struct tifm_driver *fm_drv = container_of(drv, struct tifm_driver,
45						  driver);
46	struct tifm_device_id *ids = fm_drv->id_table;
47
48	if (ids) {
49		while (ids->type) {
50			if (tifm_dev_match(sock, ids))
51				return 1;
52			++ids;
53		}
54	}
55	return 0;
56}
57
58static int tifm_uevent(struct device *dev, struct kobj_uevent_env *env)
59{
60	struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev);
61
62	if (add_uevent_var(env, "TIFM_CARD_TYPE=%s", tifm_media_type_name(sock->type, 1)))
63		return -ENOMEM;
64
65	return 0;
66}
67
68static int tifm_device_probe(struct device *dev)
69{
70	struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev);
71	struct tifm_driver *drv = container_of(dev->driver, struct tifm_driver,
72					       driver);
73	int rc = -ENODEV;
74
75	get_device(dev);
76	if (dev->driver && drv->probe) {
77		rc = drv->probe(sock);
78		if (!rc)
79			return 0;
80	}
81	put_device(dev);
82	return rc;
83}
84
85static void tifm_dummy_event(struct tifm_dev *sock)
86{
87	return;
88}
89
90static int tifm_device_remove(struct device *dev)
91{
92	struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev);
93	struct tifm_driver *drv = container_of(dev->driver, struct tifm_driver,
94					       driver);
95
96	if (dev->driver && drv->remove) {
97		sock->card_event = tifm_dummy_event;
98		sock->data_event = tifm_dummy_event;
99		drv->remove(sock);
100		sock->dev.driver = NULL;
101	}
102
103	put_device(dev);
104	return 0;
105}
106
107#ifdef CONFIG_PM
108
109static int tifm_device_suspend(struct device *dev, pm_message_t state)
110{
111	struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev);
112	struct tifm_driver *drv = container_of(dev->driver, struct tifm_driver,
113					       driver);
114
115	if (dev->driver && drv->suspend)
116		return drv->suspend(sock, state);
117	return 0;
118}
119
120static int tifm_device_resume(struct device *dev)
121{
122	struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev);
123	struct tifm_driver *drv = container_of(dev->driver, struct tifm_driver,
124					       driver);
125
126	if (dev->driver && drv->resume)
127		return drv->resume(sock);
128	return 0;
129}
130
131#else
132
133#define tifm_device_suspend NULL
134#define tifm_device_resume NULL
135
136#endif /* CONFIG_PM */
137
138static ssize_t type_show(struct device *dev, struct device_attribute *attr,
139			 char *buf)
140{
141	struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev);
142	return sprintf(buf, "%x", sock->type);
143}
144static DEVICE_ATTR_RO(type);
145
146static struct attribute *tifm_dev_attrs[] = {
147	&dev_attr_type.attr,
148	NULL,
149};
150ATTRIBUTE_GROUPS(tifm_dev);
151
152static struct bus_type tifm_bus_type = {
153	.name      = "tifm",
154	.dev_groups = tifm_dev_groups,
155	.match     = tifm_bus_match,
156	.uevent    = tifm_uevent,
157	.probe     = tifm_device_probe,
158	.remove    = tifm_device_remove,
159	.suspend   = tifm_device_suspend,
160	.resume    = tifm_device_resume
161};
162
163static void tifm_free(struct device *dev)
164{
165	struct tifm_adapter *fm = container_of(dev, struct tifm_adapter, dev);
166
167	kfree(fm);
168}
169
170static struct class tifm_adapter_class = {
171	.name    = "tifm_adapter",
172	.dev_release = tifm_free
173};
174
175struct tifm_adapter *tifm_alloc_adapter(unsigned int num_sockets,
176					struct device *dev)
177{
178	struct tifm_adapter *fm;
179
180	fm = kzalloc(sizeof(struct tifm_adapter)
181		     + sizeof(struct tifm_dev*) * num_sockets, GFP_KERNEL);
182	if (fm) {
183		fm->dev.class = &tifm_adapter_class;
184		fm->dev.parent = dev;
185		device_initialize(&fm->dev);
186		spin_lock_init(&fm->lock);
187		fm->num_sockets = num_sockets;
188	}
189	return fm;
190}
191EXPORT_SYMBOL(tifm_alloc_adapter);
192
193int tifm_add_adapter(struct tifm_adapter *fm)
194{
195	int rc;
196
197	idr_preload(GFP_KERNEL);
198	spin_lock(&tifm_adapter_lock);
199	rc = idr_alloc(&tifm_adapter_idr, fm, 0, 0, GFP_NOWAIT);
200	if (rc >= 0)
201		fm->id = rc;
202	spin_unlock(&tifm_adapter_lock);
203	idr_preload_end();
204	if (rc < 0)
205		return rc;
206
207	dev_set_name(&fm->dev, "tifm%u", fm->id);
208	rc = device_add(&fm->dev);
209	if (rc) {
210		spin_lock(&tifm_adapter_lock);
211		idr_remove(&tifm_adapter_idr, fm->id);
212		spin_unlock(&tifm_adapter_lock);
213	}
214
215	return rc;
216}
217EXPORT_SYMBOL(tifm_add_adapter);
218
219void tifm_remove_adapter(struct tifm_adapter *fm)
220{
221	unsigned int cnt;
222
223	flush_workqueue(workqueue);
224	for (cnt = 0; cnt < fm->num_sockets; ++cnt) {
225		if (fm->sockets[cnt])
226			device_unregister(&fm->sockets[cnt]->dev);
227	}
228
229	spin_lock(&tifm_adapter_lock);
230	idr_remove(&tifm_adapter_idr, fm->id);
231	spin_unlock(&tifm_adapter_lock);
232	device_del(&fm->dev);
233}
234EXPORT_SYMBOL(tifm_remove_adapter);
235
236void tifm_free_adapter(struct tifm_adapter *fm)
237{
238	put_device(&fm->dev);
239}
240EXPORT_SYMBOL(tifm_free_adapter);
241
242void tifm_free_device(struct device *dev)
243{
244	struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev);
245	kfree(sock);
246}
247EXPORT_SYMBOL(tifm_free_device);
248
249struct tifm_dev *tifm_alloc_device(struct tifm_adapter *fm, unsigned int id,
250				   unsigned char type)
251{
252	struct tifm_dev *sock = NULL;
253
254	if (!tifm_media_type_name(type, 0))
255		return sock;
256
257	sock = kzalloc(sizeof(struct tifm_dev), GFP_KERNEL);
258	if (sock) {
259		spin_lock_init(&sock->lock);
260		sock->type = type;
261		sock->socket_id = id;
262		sock->card_event = tifm_dummy_event;
263		sock->data_event = tifm_dummy_event;
264
265		sock->dev.parent = fm->dev.parent;
266		sock->dev.bus = &tifm_bus_type;
267		sock->dev.dma_mask = fm->dev.parent->dma_mask;
268		sock->dev.release = tifm_free_device;
269
270		dev_set_name(&sock->dev, "tifm_%s%u:%u",
271			     tifm_media_type_name(type, 2), fm->id, id);
272		printk(KERN_INFO DRIVER_NAME
273		       ": %s card detected in socket %u:%u\n",
274		       tifm_media_type_name(type, 0), fm->id, id);
275	}
276	return sock;
277}
278EXPORT_SYMBOL(tifm_alloc_device);
279
280void tifm_eject(struct tifm_dev *sock)
281{
282	struct tifm_adapter *fm = dev_get_drvdata(sock->dev.parent);
283	fm->eject(fm, sock);
284}
285EXPORT_SYMBOL(tifm_eject);
286
287int tifm_has_ms_pif(struct tifm_dev *sock)
288{
289	struct tifm_adapter *fm = dev_get_drvdata(sock->dev.parent);
290	return fm->has_ms_pif(fm, sock);
291}
292EXPORT_SYMBOL(tifm_has_ms_pif);
293
294int tifm_map_sg(struct tifm_dev *sock, struct scatterlist *sg, int nents,
295		int direction)
296{
297	return pci_map_sg(to_pci_dev(sock->dev.parent), sg, nents, direction);
298}
299EXPORT_SYMBOL(tifm_map_sg);
300
301void tifm_unmap_sg(struct tifm_dev *sock, struct scatterlist *sg, int nents,
302		   int direction)
303{
304	pci_unmap_sg(to_pci_dev(sock->dev.parent), sg, nents, direction);
305}
306EXPORT_SYMBOL(tifm_unmap_sg);
307
308void tifm_queue_work(struct work_struct *work)
309{
310	queue_work(workqueue, work);
311}
312EXPORT_SYMBOL(tifm_queue_work);
313
314int tifm_register_driver(struct tifm_driver *drv)
315{
316	drv->driver.bus = &tifm_bus_type;
317
318	return driver_register(&drv->driver);
319}
320EXPORT_SYMBOL(tifm_register_driver);
321
322void tifm_unregister_driver(struct tifm_driver *drv)
323{
324	driver_unregister(&drv->driver);
325}
326EXPORT_SYMBOL(tifm_unregister_driver);
327
328static int __init tifm_init(void)
329{
330	int rc;
331
332	workqueue = create_freezable_workqueue("tifm");
333	if (!workqueue)
334		return -ENOMEM;
335
336	rc = bus_register(&tifm_bus_type);
337
338	if (rc)
339		goto err_out_wq;
340
341	rc = class_register(&tifm_adapter_class);
342	if (!rc)
343		return 0;
344
345	bus_unregister(&tifm_bus_type);
346
347err_out_wq:
348	destroy_workqueue(workqueue);
349
350	return rc;
351}
352
353static void __exit tifm_exit(void)
354{
355	class_unregister(&tifm_adapter_class);
356	bus_unregister(&tifm_bus_type);
357	destroy_workqueue(workqueue);
358}
359
360subsys_initcall(tifm_init);
361module_exit(tifm_exit);
362
363MODULE_LICENSE("GPL");
364MODULE_AUTHOR("Alex Dubov");
365MODULE_DESCRIPTION("TI FlashMedia core driver");
366MODULE_LICENSE("GPL");
367MODULE_VERSION(DRIVER_VERSION);
368