blob: e90d45dec168d00c3f36059eac3e5a1c0958cfeb [file] [log] [blame]
Jeremy Kerr0508ad12017-02-01 10:53:41 -06001/*
2 * FSI core driver
3 *
4 * Copyright (C) IBM Corporation 2016
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16#include <linux/device.h>
17#include <linux/fsi.h>
Jeremy Kerr09aecfa2017-06-06 16:08:36 -050018#include <linux/idr.h>
Jeremy Kerr0508ad12017-02-01 10:53:41 -060019#include <linux/module.h>
20
Jeremy Kerr09aecfa2017-06-06 16:08:36 -050021#include "fsi-master.h"
22
23static DEFINE_IDA(master_ida);
24
Jeremy Kerrfaf0b1162017-06-06 16:08:37 -050025struct fsi_slave {
26 struct device dev;
27 struct fsi_master *master;
28 int id;
29 int link;
30 uint32_t size; /* size of slave address space */
31};
32
33#define to_fsi_slave(d) container_of(d, struct fsi_slave, dev)
34
Jeremy Kerr414c1022017-06-06 16:08:38 -050035/* FSI slave support */
36static int fsi_slave_init(struct fsi_master *master, int link, uint8_t id)
37{
38 /* todo: initialise slave device, perform engine scan */
39
40 return -ENODEV;
41}
42
Jeremy Kerr09aecfa2017-06-06 16:08:36 -050043/* FSI master support */
Jeremy Kerr414c1022017-06-06 16:08:38 -050044static int fsi_master_scan(struct fsi_master *master)
45{
46 int link;
47
48 for (link = 0; link < master->n_links; link++)
49 fsi_slave_init(master, link, 0);
50
51 return 0;
52}
53
Jeremy Kerr09aecfa2017-06-06 16:08:36 -050054int fsi_master_register(struct fsi_master *master)
55{
56 int rc;
57
58 if (!master)
59 return -EINVAL;
60
61 master->idx = ida_simple_get(&master_ida, 0, INT_MAX, GFP_KERNEL);
62 dev_set_name(&master->dev, "fsi%d", master->idx);
63
64 rc = device_register(&master->dev);
Jeremy Kerr414c1022017-06-06 16:08:38 -050065 if (rc) {
Jeremy Kerr09aecfa2017-06-06 16:08:36 -050066 ida_simple_remove(&master_ida, master->idx);
Jeremy Kerr414c1022017-06-06 16:08:38 -050067 return rc;
68 }
Jeremy Kerr09aecfa2017-06-06 16:08:36 -050069
Jeremy Kerr414c1022017-06-06 16:08:38 -050070 fsi_master_scan(master);
71 return 0;
Jeremy Kerr09aecfa2017-06-06 16:08:36 -050072}
73EXPORT_SYMBOL_GPL(fsi_master_register);
74
75void fsi_master_unregister(struct fsi_master *master)
76{
77 if (master->idx >= 0) {
78 ida_simple_remove(&master_ida, master->idx);
79 master->idx = -1;
80 }
81
82 device_unregister(&master->dev);
83}
84EXPORT_SYMBOL_GPL(fsi_master_unregister);
85
Jeremy Kerr0508ad12017-02-01 10:53:41 -060086/* FSI core & Linux bus type definitions */
87
Jeremy Kerrdd37eed2017-02-01 10:53:43 -060088static int fsi_bus_match(struct device *dev, struct device_driver *drv)
89{
90 struct fsi_device *fsi_dev = to_fsi_dev(dev);
91 struct fsi_driver *fsi_drv = to_fsi_drv(drv);
92 const struct fsi_device_id *id;
93
94 if (!fsi_drv->id_table)
95 return 0;
96
97 for (id = fsi_drv->id_table; id->engine_type; id++) {
98 if (id->engine_type != fsi_dev->engine_type)
99 continue;
100 if (id->version == FSI_VERSION_ANY ||
101 id->version == fsi_dev->version)
102 return 1;
103 }
104
105 return 0;
106}
107
Jeremy Kerr0508ad12017-02-01 10:53:41 -0600108struct bus_type fsi_bus_type = {
109 .name = "fsi",
Jeremy Kerrdd37eed2017-02-01 10:53:43 -0600110 .match = fsi_bus_match,
Jeremy Kerr0508ad12017-02-01 10:53:41 -0600111};
112EXPORT_SYMBOL_GPL(fsi_bus_type);
113
114static int fsi_init(void)
115{
116 return bus_register(&fsi_bus_type);
117}
118
119static void fsi_exit(void)
120{
121 bus_unregister(&fsi_bus_type);
122}
123
124module_init(fsi_init);
125module_exit(fsi_exit);