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