xref: /openbmc/linux/drivers/fsi/fsi-core.c (revision 414c1026)
10508ad1fSJeremy Kerr /*
20508ad1fSJeremy Kerr  * FSI core driver
30508ad1fSJeremy Kerr  *
40508ad1fSJeremy Kerr  * Copyright (C) IBM Corporation 2016
50508ad1fSJeremy Kerr  *
60508ad1fSJeremy Kerr  * This program is free software; you can redistribute it and/or modify
70508ad1fSJeremy Kerr  * it under the terms of the GNU General Public License version 2 as
80508ad1fSJeremy Kerr  * published by the Free Software Foundation.
90508ad1fSJeremy Kerr  *
100508ad1fSJeremy Kerr  * This program is distributed in the hope that it will be useful,
110508ad1fSJeremy Kerr  * but WITHOUT ANY WARRANTY; without even the implied warranty of
120508ad1fSJeremy Kerr  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
130508ad1fSJeremy Kerr  * GNU General Public License for more details.
140508ad1fSJeremy Kerr  */
150508ad1fSJeremy Kerr 
160508ad1fSJeremy Kerr #include <linux/device.h>
170508ad1fSJeremy Kerr #include <linux/fsi.h>
1809aecfabSJeremy Kerr #include <linux/idr.h>
190508ad1fSJeremy Kerr #include <linux/module.h>
200508ad1fSJeremy Kerr 
2109aecfabSJeremy Kerr #include "fsi-master.h"
2209aecfabSJeremy Kerr 
2309aecfabSJeremy Kerr static DEFINE_IDA(master_ida);
2409aecfabSJeremy Kerr 
25faf0b116SJeremy Kerr struct fsi_slave {
26faf0b116SJeremy Kerr 	struct device		dev;
27faf0b116SJeremy Kerr 	struct fsi_master	*master;
28faf0b116SJeremy Kerr 	int			id;
29faf0b116SJeremy Kerr 	int			link;
30faf0b116SJeremy Kerr 	uint32_t		size;	/* size of slave address space */
31faf0b116SJeremy Kerr };
32faf0b116SJeremy Kerr 
33faf0b116SJeremy Kerr #define to_fsi_slave(d) container_of(d, struct fsi_slave, dev)
34faf0b116SJeremy Kerr 
35414c1026SJeremy Kerr /* FSI slave support */
36414c1026SJeremy Kerr static int fsi_slave_init(struct fsi_master *master, int link, uint8_t id)
37414c1026SJeremy Kerr {
38414c1026SJeremy Kerr 	/* todo: initialise slave device, perform engine scan */
39414c1026SJeremy Kerr 
40414c1026SJeremy Kerr 	return -ENODEV;
41414c1026SJeremy Kerr }
42414c1026SJeremy Kerr 
4309aecfabSJeremy Kerr /* FSI master support */
44414c1026SJeremy Kerr static int fsi_master_scan(struct fsi_master *master)
45414c1026SJeremy Kerr {
46414c1026SJeremy Kerr 	int link;
47414c1026SJeremy Kerr 
48414c1026SJeremy Kerr 	for (link = 0; link < master->n_links; link++)
49414c1026SJeremy Kerr 		fsi_slave_init(master, link, 0);
50414c1026SJeremy Kerr 
51414c1026SJeremy Kerr 	return 0;
52414c1026SJeremy Kerr }
53414c1026SJeremy Kerr 
5409aecfabSJeremy Kerr int fsi_master_register(struct fsi_master *master)
5509aecfabSJeremy Kerr {
5609aecfabSJeremy Kerr 	int rc;
5709aecfabSJeremy Kerr 
5809aecfabSJeremy Kerr 	if (!master)
5909aecfabSJeremy Kerr 		return -EINVAL;
6009aecfabSJeremy Kerr 
6109aecfabSJeremy Kerr 	master->idx = ida_simple_get(&master_ida, 0, INT_MAX, GFP_KERNEL);
6209aecfabSJeremy Kerr 	dev_set_name(&master->dev, "fsi%d", master->idx);
6309aecfabSJeremy Kerr 
6409aecfabSJeremy Kerr 	rc = device_register(&master->dev);
65414c1026SJeremy Kerr 	if (rc) {
6609aecfabSJeremy Kerr 		ida_simple_remove(&master_ida, master->idx);
6709aecfabSJeremy Kerr 		return rc;
6809aecfabSJeremy Kerr 	}
69414c1026SJeremy Kerr 
70414c1026SJeremy Kerr 	fsi_master_scan(master);
71414c1026SJeremy Kerr 	return 0;
72414c1026SJeremy Kerr }
7309aecfabSJeremy Kerr EXPORT_SYMBOL_GPL(fsi_master_register);
7409aecfabSJeremy Kerr 
7509aecfabSJeremy Kerr void fsi_master_unregister(struct fsi_master *master)
7609aecfabSJeremy Kerr {
7709aecfabSJeremy Kerr 	if (master->idx >= 0) {
7809aecfabSJeremy Kerr 		ida_simple_remove(&master_ida, master->idx);
7909aecfabSJeremy Kerr 		master->idx = -1;
8009aecfabSJeremy Kerr 	}
8109aecfabSJeremy Kerr 
8209aecfabSJeremy Kerr 	device_unregister(&master->dev);
8309aecfabSJeremy Kerr }
8409aecfabSJeremy Kerr EXPORT_SYMBOL_GPL(fsi_master_unregister);
8509aecfabSJeremy Kerr 
860508ad1fSJeremy Kerr /* FSI core & Linux bus type definitions */
870508ad1fSJeremy Kerr 
88dd37eed7SJeremy Kerr static int fsi_bus_match(struct device *dev, struct device_driver *drv)
89dd37eed7SJeremy Kerr {
90dd37eed7SJeremy Kerr 	struct fsi_device *fsi_dev = to_fsi_dev(dev);
91dd37eed7SJeremy Kerr 	struct fsi_driver *fsi_drv = to_fsi_drv(drv);
92dd37eed7SJeremy Kerr 	const struct fsi_device_id *id;
93dd37eed7SJeremy Kerr 
94dd37eed7SJeremy Kerr 	if (!fsi_drv->id_table)
95dd37eed7SJeremy Kerr 		return 0;
96dd37eed7SJeremy Kerr 
97dd37eed7SJeremy Kerr 	for (id = fsi_drv->id_table; id->engine_type; id++) {
98dd37eed7SJeremy Kerr 		if (id->engine_type != fsi_dev->engine_type)
99dd37eed7SJeremy Kerr 			continue;
100dd37eed7SJeremy Kerr 		if (id->version == FSI_VERSION_ANY ||
101dd37eed7SJeremy Kerr 				id->version == fsi_dev->version)
102dd37eed7SJeremy Kerr 			return 1;
103dd37eed7SJeremy Kerr 	}
104dd37eed7SJeremy Kerr 
105dd37eed7SJeremy Kerr 	return 0;
106dd37eed7SJeremy Kerr }
107dd37eed7SJeremy Kerr 
1080508ad1fSJeremy Kerr struct bus_type fsi_bus_type = {
1090508ad1fSJeremy Kerr 	.name		= "fsi",
110dd37eed7SJeremy Kerr 	.match		= fsi_bus_match,
1110508ad1fSJeremy Kerr };
1120508ad1fSJeremy Kerr EXPORT_SYMBOL_GPL(fsi_bus_type);
1130508ad1fSJeremy Kerr 
1140508ad1fSJeremy Kerr static int fsi_init(void)
1150508ad1fSJeremy Kerr {
1160508ad1fSJeremy Kerr 	return bus_register(&fsi_bus_type);
1170508ad1fSJeremy Kerr }
1180508ad1fSJeremy Kerr 
1190508ad1fSJeremy Kerr static void fsi_exit(void)
1200508ad1fSJeremy Kerr {
1210508ad1fSJeremy Kerr 	bus_unregister(&fsi_bus_type);
1220508ad1fSJeremy Kerr }
1230508ad1fSJeremy Kerr 
1240508ad1fSJeremy Kerr module_init(fsi_init);
1250508ad1fSJeremy Kerr module_exit(fsi_exit);
126