1802d0beecafe (Thomas Gleixner 2019-05-27 08:55:21 +0200 1) // SPDX-License-Identifier: GPL-2.0-only
0508ad1fff11a (Jeremy Kerr 2017-02-01 10:53:41 -0600 2) /*
0508ad1fff11a (Jeremy Kerr 2017-02-01 10:53:41 -0600 3) * FSI core driver
0508ad1fff11a (Jeremy Kerr 2017-02-01 10:53:41 -0600 4) *
0508ad1fff11a (Jeremy Kerr 2017-02-01 10:53:41 -0600 5) * Copyright (C) IBM Corporation 2016
0508ad1fff11a (Jeremy Kerr 2017-02-01 10:53:41 -0600 6) *
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 7) * TODO:
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 8) * - Rework topology
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 9) * - s/chip_id/chip_loc
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 10) * - s/cfam/chip (cfam_id -> chip_id etc...)
0508ad1fff11a (Jeremy Kerr 2017-02-01 10:53:41 -0600 11) */
0508ad1fff11a (Jeremy Kerr 2017-02-01 10:53:41 -0600 12)
2b545cd8e1b2a (Jeremy Kerr 2017-06-06 16:08:42 -0500 13) #include <linux/crc4.h>
0508ad1fff11a (Jeremy Kerr 2017-02-01 10:53:41 -0600 14) #include <linux/device.h>
0508ad1fff11a (Jeremy Kerr 2017-02-01 10:53:41 -0600 15) #include <linux/fsi.h>
09aecfab93b8f (Jeremy Kerr 2017-06-06 16:08:36 -0500 16) #include <linux/idr.h>
0508ad1fff11a (Jeremy Kerr 2017-02-01 10:53:41 -0600 17) #include <linux/module.h>
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 18) #include <linux/of.h>
2b545cd8e1b2a (Jeremy Kerr 2017-06-06 16:08:42 -0500 19) #include <linux/slab.h>
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 20) #include <linux/bitops.h>
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 21) #include <linux/cdev.h>
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 22) #include <linux/fs.h>
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 23) #include <linux/uaccess.h>
0508ad1fff11a (Jeremy Kerr 2017-02-01 10:53:41 -0600 24)
09aecfab93b8f (Jeremy Kerr 2017-06-06 16:08:36 -0500 25) #include "fsi-master.h"
09aecfab93b8f (Jeremy Kerr 2017-06-06 16:08:36 -0500 26)
66433b05a3b2b (Jeremy Kerr 2017-06-06 16:08:51 -0500 27) #define CREATE_TRACE_POINTS
66433b05a3b2b (Jeremy Kerr 2017-06-06 16:08:51 -0500 28) #include <trace/events/fsi.h>
66433b05a3b2b (Jeremy Kerr 2017-06-06 16:08:51 -0500 29)
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 30) #define FSI_SLAVE_CONF_NEXT_MASK GENMASK(31, 31)
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 31) #define FSI_SLAVE_CONF_SLOTS_MASK GENMASK(23, 16)
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 32) #define FSI_SLAVE_CONF_SLOTS_SHIFT 16
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 33) #define FSI_SLAVE_CONF_VERSION_MASK GENMASK(15, 12)
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 34) #define FSI_SLAVE_CONF_VERSION_SHIFT 12
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 35) #define FSI_SLAVE_CONF_TYPE_MASK GENMASK(11, 4)
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 36) #define FSI_SLAVE_CONF_TYPE_SHIFT 4
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 37) #define FSI_SLAVE_CONF_CRC_SHIFT 4
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 38) #define FSI_SLAVE_CONF_CRC_MASK GENMASK(3, 0)
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 39) #define FSI_SLAVE_CONF_DATA_BITS 28
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 40)
4efe37f4c4efc (Jeremy Kerr 2017-06-06 16:08:45 -0500 41) #define FSI_PEEK_BASE 0x410
4efe37f4c4efc (Jeremy Kerr 2017-06-06 16:08:45 -0500 42)
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 43) static const int engine_page_size = 0x400;
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 44)
2b37c3e285f9d (Christopher Bostic 2017-06-06 16:08:43 -0500 45) #define FSI_SLAVE_BASE 0x800
2b37c3e285f9d (Christopher Bostic 2017-06-06 16:08:43 -0500 46)
2b37c3e285f9d (Christopher Bostic 2017-06-06 16:08:43 -0500 47) /*
2b37c3e285f9d (Christopher Bostic 2017-06-06 16:08:43 -0500 48) * FSI slave engine control register offsets
2b37c3e285f9d (Christopher Bostic 2017-06-06 16:08:43 -0500 49) */
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 50) #define FSI_SMODE 0x0 /* R/W: Mode register */
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 51) #define FSI_SISC 0x8 /* R/W: Interrupt condition */
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 52) #define FSI_SSTAT 0x14 /* R : Slave status */
196964a31cf8c (Eddie James 2020-05-20 13:17:07 -0500 53) #define FSI_SLBUS 0x30 /* W : LBUS Ownership */
4af889b0ff78a (Jeremy Kerr 2017-06-06 16:08:58 -0500 54) #define FSI_LLMODE 0x100 /* R/W: Link layer mode register */
2b37c3e285f9d (Christopher Bostic 2017-06-06 16:08:43 -0500 55)
2b37c3e285f9d (Christopher Bostic 2017-06-06 16:08:43 -0500 56) /*
2b37c3e285f9d (Christopher Bostic 2017-06-06 16:08:43 -0500 57) * SMODE fields
2b37c3e285f9d (Christopher Bostic 2017-06-06 16:08:43 -0500 58) */
2b37c3e285f9d (Christopher Bostic 2017-06-06 16:08:43 -0500 59) #define FSI_SMODE_WSC 0x80000000 /* Warm start done */
2b37c3e285f9d (Christopher Bostic 2017-06-06 16:08:43 -0500 60) #define FSI_SMODE_ECRC 0x20000000 /* Hw CRC check */
2b37c3e285f9d (Christopher Bostic 2017-06-06 16:08:43 -0500 61) #define FSI_SMODE_SID_SHIFT 24 /* ID shift */
2b37c3e285f9d (Christopher Bostic 2017-06-06 16:08:43 -0500 62) #define FSI_SMODE_SID_MASK 3 /* ID Mask */
2b37c3e285f9d (Christopher Bostic 2017-06-06 16:08:43 -0500 63) #define FSI_SMODE_ED_SHIFT 20 /* Echo delay shift */
2b37c3e285f9d (Christopher Bostic 2017-06-06 16:08:43 -0500 64) #define FSI_SMODE_ED_MASK 0xf /* Echo delay mask */
2b37c3e285f9d (Christopher Bostic 2017-06-06 16:08:43 -0500 65) #define FSI_SMODE_SD_SHIFT 16 /* Send delay shift */
2b37c3e285f9d (Christopher Bostic 2017-06-06 16:08:43 -0500 66) #define FSI_SMODE_SD_MASK 0xf /* Send delay mask */
2b37c3e285f9d (Christopher Bostic 2017-06-06 16:08:43 -0500 67) #define FSI_SMODE_LBCRR_SHIFT 8 /* Clk ratio shift */
2b37c3e285f9d (Christopher Bostic 2017-06-06 16:08:43 -0500 68) #define FSI_SMODE_LBCRR_MASK 0xf /* Clk ratio mask */
2b37c3e285f9d (Christopher Bostic 2017-06-06 16:08:43 -0500 69)
196964a31cf8c (Eddie James 2020-05-20 13:17:07 -0500 70) /*
196964a31cf8c (Eddie James 2020-05-20 13:17:07 -0500 71) * SLBUS fields
196964a31cf8c (Eddie James 2020-05-20 13:17:07 -0500 72) */
196964a31cf8c (Eddie James 2020-05-20 13:17:07 -0500 73) #define FSI_SLBUS_FORCE 0x80000000 /* Force LBUS ownership */
196964a31cf8c (Eddie James 2020-05-20 13:17:07 -0500 74)
4af889b0ff78a (Jeremy Kerr 2017-06-06 16:08:58 -0500 75) /*
4af889b0ff78a (Jeremy Kerr 2017-06-06 16:08:58 -0500 76) * LLMODE fields
4af889b0ff78a (Jeremy Kerr 2017-06-06 16:08:58 -0500 77) */
4af889b0ff78a (Jeremy Kerr 2017-06-06 16:08:58 -0500 78) #define FSI_LLMODE_ASYNC 0x1
4af889b0ff78a (Jeremy Kerr 2017-06-06 16:08:58 -0500 79)
2b545cd8e1b2a (Jeremy Kerr 2017-06-06 16:08:42 -0500 80) #define FSI_SLAVE_SIZE_23b 0x800000
2b545cd8e1b2a (Jeremy Kerr 2017-06-06 16:08:42 -0500 81)
09aecfab93b8f (Jeremy Kerr 2017-06-06 16:08:36 -0500 82) static DEFINE_IDA(master_ida);
09aecfab93b8f (Jeremy Kerr 2017-06-06 16:08:36 -0500 83)
faf0b116dec11 (Jeremy Kerr 2017-06-06 16:08:37 -0500 84) struct fsi_slave {
faf0b116dec11 (Jeremy Kerr 2017-06-06 16:08:37 -0500 85) struct device dev;
faf0b116dec11 (Jeremy Kerr 2017-06-06 16:08:37 -0500 86) struct fsi_master *master;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 87) struct cdev cdev;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 88) int cdev_idx;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 89) int id; /* FSI address */
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 90) int link; /* FSI link# */
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 91) u32 cfam_id;
0a213777d1dd8 (Benjamin Herrenschmidt 2018-06-20 15:16:31 +1000 92) int chip_id;
faf0b116dec11 (Jeremy Kerr 2017-06-06 16:08:37 -0500 93) uint32_t size; /* size of slave address space */
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 94) u8 t_send_delay;
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 95) u8 t_echo_delay;
faf0b116dec11 (Jeremy Kerr 2017-06-06 16:08:37 -0500 96) };
faf0b116dec11 (Jeremy Kerr 2017-06-06 16:08:37 -0500 97)
cd0fdb5c07b27 (Christopher Bostic 2017-06-06 16:08:46 -0500 98) #define to_fsi_master(d) container_of(d, struct fsi_master, dev)
faf0b116dec11 (Jeremy Kerr 2017-06-06 16:08:37 -0500 99) #define to_fsi_slave(d) container_of(d, struct fsi_slave, dev)
faf0b116dec11 (Jeremy Kerr 2017-06-06 16:08:37 -0500 100)
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 101) static const int slave_retries = 2;
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 102) static int discard_errors;
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 103)
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 104) static dev_t fsi_base_dev;
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 105) static DEFINE_IDA(fsi_minor_ida);
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 106) #define FSI_CHAR_MAX_DEVICES 0x1000
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 107)
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 108) /* Legacy /dev numbering: 4 devices per chip, 16 chips */
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 109) #define FSI_CHAR_LEGACY_TOP 64
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 110)
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 111) static int fsi_master_read(struct fsi_master *master, int link,
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 112) uint8_t slave_id, uint32_t addr, void *val, size_t size);
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 113) static int fsi_master_write(struct fsi_master *master, int link,
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 114) uint8_t slave_id, uint32_t addr, const void *val, size_t size);
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 115) static int fsi_master_break(struct fsi_master *master, int link);
4efe37f4c4efc (Jeremy Kerr 2017-06-06 16:08:45 -0500 116)
4efe37f4c4efc (Jeremy Kerr 2017-06-06 16:08:45 -0500 117) /*
4efe37f4c4efc (Jeremy Kerr 2017-06-06 16:08:45 -0500 118) * fsi_device_read() / fsi_device_write() / fsi_device_peek()
4efe37f4c4efc (Jeremy Kerr 2017-06-06 16:08:45 -0500 119) *
4efe37f4c4efc (Jeremy Kerr 2017-06-06 16:08:45 -0500 120) * FSI endpoint-device support
4efe37f4c4efc (Jeremy Kerr 2017-06-06 16:08:45 -0500 121) *
4efe37f4c4efc (Jeremy Kerr 2017-06-06 16:08:45 -0500 122) * Read / write / peek accessors for a client
4efe37f4c4efc (Jeremy Kerr 2017-06-06 16:08:45 -0500 123) *
4efe37f4c4efc (Jeremy Kerr 2017-06-06 16:08:45 -0500 124) * Parameters:
4efe37f4c4efc (Jeremy Kerr 2017-06-06 16:08:45 -0500 125) * dev: Structure passed to FSI client device drivers on probe().
4efe37f4c4efc (Jeremy Kerr 2017-06-06 16:08:45 -0500 126) * addr: FSI address of given device. Client should pass in its base address
4efe37f4c4efc (Jeremy Kerr 2017-06-06 16:08:45 -0500 127) * plus desired offset to access its register space.
4efe37f4c4efc (Jeremy Kerr 2017-06-06 16:08:45 -0500 128) * val: For read/peek this is the value read at the specified address. For
4efe37f4c4efc (Jeremy Kerr 2017-06-06 16:08:45 -0500 129) * write this is value to write to the specified address.
4efe37f4c4efc (Jeremy Kerr 2017-06-06 16:08:45 -0500 130) * The data in val must be FSI bus endian (big endian).
4efe37f4c4efc (Jeremy Kerr 2017-06-06 16:08:45 -0500 131) * size: Size in bytes of the operation. Sizes supported are 1, 2 and 4 bytes.
4efe37f4c4efc (Jeremy Kerr 2017-06-06 16:08:45 -0500 132) * Addresses must be aligned on size boundaries or an error will result.
4efe37f4c4efc (Jeremy Kerr 2017-06-06 16:08:45 -0500 133) */
4efe37f4c4efc (Jeremy Kerr 2017-06-06 16:08:45 -0500 134) int fsi_device_read(struct fsi_device *dev, uint32_t addr, void *val,
4efe37f4c4efc (Jeremy Kerr 2017-06-06 16:08:45 -0500 135) size_t size)
4efe37f4c4efc (Jeremy Kerr 2017-06-06 16:08:45 -0500 136) {
4efe37f4c4efc (Jeremy Kerr 2017-06-06 16:08:45 -0500 137) if (addr > dev->size || size > dev->size || addr > dev->size - size)
4efe37f4c4efc (Jeremy Kerr 2017-06-06 16:08:45 -0500 138) return -EINVAL;
4efe37f4c4efc (Jeremy Kerr 2017-06-06 16:08:45 -0500 139)
4efe37f4c4efc (Jeremy Kerr 2017-06-06 16:08:45 -0500 140) return fsi_slave_read(dev->slave, dev->addr + addr, val, size);
4efe37f4c4efc (Jeremy Kerr 2017-06-06 16:08:45 -0500 141) }
4efe37f4c4efc (Jeremy Kerr 2017-06-06 16:08:45 -0500 142) EXPORT_SYMBOL_GPL(fsi_device_read);
4efe37f4c4efc (Jeremy Kerr 2017-06-06 16:08:45 -0500 143)
4efe37f4c4efc (Jeremy Kerr 2017-06-06 16:08:45 -0500 144) int fsi_device_write(struct fsi_device *dev, uint32_t addr, const void *val,
4efe37f4c4efc (Jeremy Kerr 2017-06-06 16:08:45 -0500 145) size_t size)
4efe37f4c4efc (Jeremy Kerr 2017-06-06 16:08:45 -0500 146) {
4efe37f4c4efc (Jeremy Kerr 2017-06-06 16:08:45 -0500 147) if (addr > dev->size || size > dev->size || addr > dev->size - size)
4efe37f4c4efc (Jeremy Kerr 2017-06-06 16:08:45 -0500 148) return -EINVAL;
4efe37f4c4efc (Jeremy Kerr 2017-06-06 16:08:45 -0500 149)
4efe37f4c4efc (Jeremy Kerr 2017-06-06 16:08:45 -0500 150) return fsi_slave_write(dev->slave, dev->addr + addr, val, size);
4efe37f4c4efc (Jeremy Kerr 2017-06-06 16:08:45 -0500 151) }
4efe37f4c4efc (Jeremy Kerr 2017-06-06 16:08:45 -0500 152) EXPORT_SYMBOL_GPL(fsi_device_write);
4efe37f4c4efc (Jeremy Kerr 2017-06-06 16:08:45 -0500 153)
4efe37f4c4efc (Jeremy Kerr 2017-06-06 16:08:45 -0500 154) int fsi_device_peek(struct fsi_device *dev, void *val)
4efe37f4c4efc (Jeremy Kerr 2017-06-06 16:08:45 -0500 155) {
4efe37f4c4efc (Jeremy Kerr 2017-06-06 16:08:45 -0500 156) uint32_t addr = FSI_PEEK_BASE + ((dev->unit - 2) * sizeof(uint32_t));
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 157)
4efe37f4c4efc (Jeremy Kerr 2017-06-06 16:08:45 -0500 158) return fsi_slave_read(dev->slave, addr, val, sizeof(uint32_t));
4efe37f4c4efc (Jeremy Kerr 2017-06-06 16:08:45 -0500 159) }
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 160)
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 161) static void fsi_device_release(struct device *_device)
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 162) {
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 163) struct fsi_device *device = to_fsi_dev(_device);
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 164)
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 165) of_node_put(device->dev.of_node);
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 166) kfree(device);
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 167) }
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 168)
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 169) static struct fsi_device *fsi_create_device(struct fsi_slave *slave)
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 170) {
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 171) struct fsi_device *dev;
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 172)
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 173) dev = kzalloc(sizeof(*dev), GFP_KERNEL);
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 174) if (!dev)
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 175) return NULL;
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 176)
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 177) dev->dev.parent = &slave->dev;
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 178) dev->dev.bus = &fsi_bus_type;
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 179) dev->dev.release = fsi_device_release;
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 180)
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 181) return dev;
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 182) }
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 183)
414c1026319bc (Jeremy Kerr 2017-06-06 16:08:38 -0500 184) /* FSI slave support */
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 185) static int fsi_slave_calc_addr(struct fsi_slave *slave, uint32_t *addrp,
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 186) uint8_t *idp)
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 187) {
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 188) uint32_t addr = *addrp;
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 189) uint8_t id = *idp;
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 190)
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 191) if (addr > slave->size)
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 192) return -EINVAL;
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 193)
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 194) /* For 23 bit addressing, we encode the extra two bits in the slave
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 195) * id (and the slave's actual ID needs to be 0).
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 196) */
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 197) if (addr > 0x1fffff) {
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 198) if (slave->id != 0)
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 199) return -EINVAL;
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 200) id = (addr >> 21) & 0x3;
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 201) addr &= 0x1fffff;
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 202) }
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 203)
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 204) *addrp = addr;
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 205) *idp = id;
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 206) return 0;
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 207) }
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 208)
ed50a0890eaa8 (Colin Ian King 2017-10-03 09:31:45 +0100 209) static int fsi_slave_report_and_clear_errors(struct fsi_slave *slave)
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 210) {
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 211) struct fsi_master *master = slave->master;
11454d6dc8181 (Joel Stanley 2018-06-18 13:13:35 +0930 212) __be32 irq, stat;
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 213) int rc, link;
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 214) uint8_t id;
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 215)
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 216) link = slave->link;
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 217) id = slave->id;
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 218)
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 219) rc = fsi_master_read(master, link, id, FSI_SLAVE_BASE + FSI_SISC,
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 220) &irq, sizeof(irq));
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 221) if (rc)
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 222) return rc;
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 223)
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 224) rc = fsi_master_read(master, link, id, FSI_SLAVE_BASE + FSI_SSTAT,
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 225) &stat, sizeof(stat));
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 226) if (rc)
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 227) return rc;
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 228)
638bd9ac847e8 (Christopher Bostic 2018-02-12 15:45:46 +1030 229) dev_dbg(&slave->dev, "status: 0x%08x, sisc: 0x%08x\n",
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 230) be32_to_cpu(stat), be32_to_cpu(irq));
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 231)
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 232) /* clear interrupts */
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 233) return fsi_master_write(master, link, id, FSI_SLAVE_BASE + FSI_SISC,
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 234) &irq, sizeof(irq));
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 235) }
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 236)
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000 237) /* Encode slave local bus echo delay */
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000 238) static inline uint32_t fsi_smode_echodly(int x)
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000 239) {
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000 240) return (x & FSI_SMODE_ED_MASK) << FSI_SMODE_ED_SHIFT;
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000 241) }
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000 242)
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000 243) /* Encode slave local bus send delay */
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000 244) static inline uint32_t fsi_smode_senddly(int x)
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000 245) {
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000 246) return (x & FSI_SMODE_SD_MASK) << FSI_SMODE_SD_SHIFT;
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000 247) }
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000 248)
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000 249) /* Encode slave local bus clock rate ratio */
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000 250) static inline uint32_t fsi_smode_lbcrr(int x)
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000 251) {
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000 252) return (x & FSI_SMODE_LBCRR_MASK) << FSI_SMODE_LBCRR_SHIFT;
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000 253) }
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000 254)
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000 255) /* Encode slave ID */
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000 256) static inline uint32_t fsi_smode_sid(int x)
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000 257) {
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000 258) return (x & FSI_SMODE_SID_MASK) << FSI_SMODE_SID_SHIFT;
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000 259) }
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000 260)
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 261) static uint32_t fsi_slave_smode(int id, u8 t_senddly, u8 t_echodly)
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000 262) {
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000 263) return FSI_SMODE_WSC | FSI_SMODE_ECRC
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000 264) | fsi_smode_sid(id)
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 265) | fsi_smode_echodly(t_echodly - 1) | fsi_smode_senddly(t_senddly - 1)
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000 266) | fsi_smode_lbcrr(0x8);
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000 267) }
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000 268)
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 269) static int fsi_slave_set_smode(struct fsi_slave *slave)
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000 270) {
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000 271) uint32_t smode;
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000 272) __be32 data;
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000 273)
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000 274) /* set our smode register with the slave ID field to 0; this enables
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000 275) * extended slave addressing
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000 276) */
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 277) smode = fsi_slave_smode(slave->id, slave->t_send_delay, slave->t_echo_delay);
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000 278) data = cpu_to_be32(smode);
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000 279)
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 280) return fsi_master_write(slave->master, slave->link, slave->id,
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 281) FSI_SLAVE_BASE + FSI_SMODE,
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 282) &data, sizeof(data));
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000 283) }
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 284)
ed50a0890eaa8 (Colin Ian King 2017-10-03 09:31:45 +0100 285) static int fsi_slave_handle_error(struct fsi_slave *slave, bool write,
ed50a0890eaa8 (Colin Ian King 2017-10-03 09:31:45 +0100 286) uint32_t addr, size_t size)
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 287) {
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 288) struct fsi_master *master = slave->master;
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 289) int rc, link;
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 290) uint32_t reg;
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 291) uint8_t id, send_delay, echo_delay;
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 292)
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 293) if (discard_errors)
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 294) return -1;
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 295)
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 296) link = slave->link;
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 297) id = slave->id;
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 298)
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 299) dev_dbg(&slave->dev, "handling error on %s to 0x%08x[%zd]",
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 300) write ? "write" : "read", addr, size);
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 301)
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 302) /* try a simple clear of error conditions, which may fail if we've lost
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 303) * communication with the slave
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 304) */
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 305) rc = fsi_slave_report_and_clear_errors(slave);
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 306) if (!rc)
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 307) return 0;
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 308)
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 309) /* send a TERM and retry */
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 310) if (master->term) {
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 311) rc = master->term(master, link, id);
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 312) if (!rc) {
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 313) rc = fsi_master_read(master, link, id, 0,
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 314) ®, sizeof(reg));
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 315) if (!rc)
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 316) rc = fsi_slave_report_and_clear_errors(slave);
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 317) if (!rc)
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 318) return 0;
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 319) }
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 320) }
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 321)
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 322) send_delay = slave->t_send_delay;
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 323) echo_delay = slave->t_echo_delay;
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 324)
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 325) /* getting serious, reset the slave via BREAK */
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 326) rc = fsi_master_break(master, link);
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 327) if (rc)
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 328) return rc;
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 329)
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 330) slave->t_send_delay = send_delay;
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 331) slave->t_echo_delay = echo_delay;
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 332)
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 333) rc = fsi_slave_set_smode(slave);
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 334) if (rc)
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 335) return rc;
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 336)
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 337) if (master->link_config)
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 338) master->link_config(master, link,
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 339) slave->t_send_delay,
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 340) slave->t_echo_delay);
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 341)
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 342) return fsi_slave_report_and_clear_errors(slave);
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 343) }
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 344)
da36cadf89a75 (Jeremy Kerr 2017-06-06 16:08:50 -0500 345) int fsi_slave_read(struct fsi_slave *slave, uint32_t addr,
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 346) void *val, size_t size)
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 347) {
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 348) uint8_t id = slave->id;
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 349) int rc, err_rc, i;
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 350)
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 351) rc = fsi_slave_calc_addr(slave, &addr, &id);
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 352) if (rc)
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 353) return rc;
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 354)
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 355) for (i = 0; i < slave_retries; i++) {
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 356) rc = fsi_master_read(slave->master, slave->link,
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 357) id, addr, val, size);
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 358) if (!rc)
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 359) break;
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 360)
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 361) err_rc = fsi_slave_handle_error(slave, false, addr, size);
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 362) if (err_rc)
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 363) break;
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 364) }
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 365)
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 366) return rc;
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 367) }
da36cadf89a75 (Jeremy Kerr 2017-06-06 16:08:50 -0500 368) EXPORT_SYMBOL_GPL(fsi_slave_read);
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 369)
da36cadf89a75 (Jeremy Kerr 2017-06-06 16:08:50 -0500 370) int fsi_slave_write(struct fsi_slave *slave, uint32_t addr,
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 371) const void *val, size_t size)
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 372) {
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 373) uint8_t id = slave->id;
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 374) int rc, err_rc, i;
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 375)
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 376) rc = fsi_slave_calc_addr(slave, &addr, &id);
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 377) if (rc)
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 378) return rc;
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 379)
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 380) for (i = 0; i < slave_retries; i++) {
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 381) rc = fsi_master_write(slave->master, slave->link,
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 382) id, addr, val, size);
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 383) if (!rc)
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 384) break;
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 385)
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 386) err_rc = fsi_slave_handle_error(slave, true, addr, size);
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 387) if (err_rc)
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 388) break;
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 389) }
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 390)
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 391) return rc;
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 392) }
da36cadf89a75 (Jeremy Kerr 2017-06-06 16:08:50 -0500 393) EXPORT_SYMBOL_GPL(fsi_slave_write);
da36cadf89a75 (Jeremy Kerr 2017-06-06 16:08:50 -0500 394)
da36cadf89a75 (Jeremy Kerr 2017-06-06 16:08:50 -0500 395) extern int fsi_slave_claim_range(struct fsi_slave *slave,
da36cadf89a75 (Jeremy Kerr 2017-06-06 16:08:50 -0500 396) uint32_t addr, uint32_t size)
da36cadf89a75 (Jeremy Kerr 2017-06-06 16:08:50 -0500 397) {
da36cadf89a75 (Jeremy Kerr 2017-06-06 16:08:50 -0500 398) if (addr + size < addr)
da36cadf89a75 (Jeremy Kerr 2017-06-06 16:08:50 -0500 399) return -EINVAL;
da36cadf89a75 (Jeremy Kerr 2017-06-06 16:08:50 -0500 400)
da36cadf89a75 (Jeremy Kerr 2017-06-06 16:08:50 -0500 401) if (addr + size > slave->size)
da36cadf89a75 (Jeremy Kerr 2017-06-06 16:08:50 -0500 402) return -EINVAL;
da36cadf89a75 (Jeremy Kerr 2017-06-06 16:08:50 -0500 403)
da36cadf89a75 (Jeremy Kerr 2017-06-06 16:08:50 -0500 404) /* todo: check for overlapping claims */
da36cadf89a75 (Jeremy Kerr 2017-06-06 16:08:50 -0500 405) return 0;
da36cadf89a75 (Jeremy Kerr 2017-06-06 16:08:50 -0500 406) }
da36cadf89a75 (Jeremy Kerr 2017-06-06 16:08:50 -0500 407) EXPORT_SYMBOL_GPL(fsi_slave_claim_range);
da36cadf89a75 (Jeremy Kerr 2017-06-06 16:08:50 -0500 408)
da36cadf89a75 (Jeremy Kerr 2017-06-06 16:08:50 -0500 409) extern void fsi_slave_release_range(struct fsi_slave *slave,
da36cadf89a75 (Jeremy Kerr 2017-06-06 16:08:50 -0500 410) uint32_t addr, uint32_t size)
da36cadf89a75 (Jeremy Kerr 2017-06-06 16:08:50 -0500 411) {
da36cadf89a75 (Jeremy Kerr 2017-06-06 16:08:50 -0500 412) }
da36cadf89a75 (Jeremy Kerr 2017-06-06 16:08:50 -0500 413) EXPORT_SYMBOL_GPL(fsi_slave_release_range);
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 414)
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 415) static bool fsi_device_node_matches(struct device *dev, struct device_node *np,
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 416) uint32_t addr, uint32_t size)
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 417) {
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 418) unsigned int len, na, ns;
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 419) const __be32 *prop;
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 420) uint32_t psize;
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 421)
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 422) na = of_n_addr_cells(np);
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 423) ns = of_n_size_cells(np);
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 424)
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 425) if (na != 1 || ns != 1)
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 426) return false;
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 427)
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 428) prop = of_get_property(np, "reg", &len);
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 429) if (!prop || len != 8)
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 430) return false;
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 431)
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 432) if (of_read_number(prop, 1) != addr)
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 433) return false;
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 434)
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 435) psize = of_read_number(prop + 1, 1);
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 436) if (psize != size) {
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 437) dev_warn(dev,
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 438) "node %s matches probed address, but not size (got 0x%x, expected 0x%x)",
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 439) of_node_full_name(np), psize, size);
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 440) }
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 441)
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 442) return true;
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 443) }
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 444)
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 445) /* Find a matching node for the slave engine at @address, using @size bytes
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 446) * of space. Returns NULL if not found, or a matching node with refcount
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 447) * already incremented.
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 448) */
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 449) static struct device_node *fsi_device_find_of_node(struct fsi_device *dev)
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 450) {
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 451) struct device_node *parent, *np;
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 452)
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 453) parent = dev_of_node(&dev->slave->dev);
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 454) if (!parent)
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 455) return NULL;
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 456)
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 457) for_each_child_of_node(parent, np) {
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 458) if (fsi_device_node_matches(&dev->dev, np,
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 459) dev->addr, dev->size))
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 460) return np;
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 461) }
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 462)
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 463) return NULL;
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 464) }
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 465)
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 466) static int fsi_slave_scan(struct fsi_slave *slave)
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 467) {
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 468) uint32_t engine_addr;
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 469) int rc, i;
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 470)
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 471) /*
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 472) * scan engines
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 473) *
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 474) * We keep the peek mode and slave engines for the core; so start
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 475) * at the third slot in the configuration table. We also need to
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 476) * skip the chip ID entry at the start of the address space.
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 477) */
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 478) engine_addr = engine_page_size * 3;
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 479) for (i = 2; i < engine_page_size / sizeof(uint32_t); i++) {
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 480) uint8_t slots, version, type, crc;
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 481) struct fsi_device *dev;
11454d6dc8181 (Joel Stanley 2018-06-18 13:13:35 +0930 482) uint32_t conf;
11454d6dc8181 (Joel Stanley 2018-06-18 13:13:35 +0930 483) __be32 data;
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 484)
11454d6dc8181 (Joel Stanley 2018-06-18 13:13:35 +0930 485) rc = fsi_slave_read(slave, (i + 1) * sizeof(data),
11454d6dc8181 (Joel Stanley 2018-06-18 13:13:35 +0930 486) &data, sizeof(data));
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 487) if (rc) {
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 488) dev_warn(&slave->dev,
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 489) "error reading slave registers\n");
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 490) return -1;
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 491) }
11454d6dc8181 (Joel Stanley 2018-06-18 13:13:35 +0930 492) conf = be32_to_cpu(data);
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 493)
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 494) crc = crc4(0, conf, 32);
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 495) if (crc) {
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 496) dev_warn(&slave->dev,
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 497) "crc error in slave register at 0x%04x\n",
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 498) i);
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 499) return -1;
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 500) }
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 501)
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 502) slots = (conf & FSI_SLAVE_CONF_SLOTS_MASK)
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 503) >> FSI_SLAVE_CONF_SLOTS_SHIFT;
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 504) version = (conf & FSI_SLAVE_CONF_VERSION_MASK)
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 505) >> FSI_SLAVE_CONF_VERSION_SHIFT;
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 506) type = (conf & FSI_SLAVE_CONF_TYPE_MASK)
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 507) >> FSI_SLAVE_CONF_TYPE_SHIFT;
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 508)
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 509) /*
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 510) * Unused address areas are marked by a zero type value; this
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 511) * skips the defined address areas
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 512) */
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 513) if (type != 0 && slots != 0) {
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 514)
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 515) /* create device */
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 516) dev = fsi_create_device(slave);
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 517) if (!dev)
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 518) return -ENOMEM;
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 519)
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 520) dev->slave = slave;
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 521) dev->engine_type = type;
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 522) dev->version = version;
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 523) dev->unit = i;
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 524) dev->addr = engine_addr;
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 525) dev->size = slots * engine_page_size;
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 526)
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 527) dev_dbg(&slave->dev,
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 528) "engine[%i]: type %x, version %x, addr %x size %x\n",
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 529) dev->unit, dev->engine_type, version,
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 530) dev->addr, dev->size);
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 531)
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 532) dev_set_name(&dev->dev, "%02x:%02x:%02x:%02x",
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 533) slave->master->idx, slave->link,
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 534) slave->id, i - 2);
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 535) dev->dev.of_node = fsi_device_find_of_node(dev);
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 536)
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 537) rc = device_register(&dev->dev);
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 538) if (rc) {
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 539) dev_warn(&slave->dev, "add failed: %d\n", rc);
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 540) put_device(&dev->dev);
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 541) }
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 542) }
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 543)
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 544) engine_addr += slots * engine_page_size;
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 545)
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 546) if (!(conf & FSI_SLAVE_CONF_NEXT_MASK))
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 547) break;
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 548) }
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 549)
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 550) return 0;
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 551) }
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 552)
9f4c2b516b4f0 (Andrew Jeffery 2019-11-08 15:49:39 +1030 553) static unsigned long aligned_access_size(size_t offset, size_t count)
9f4c2b516b4f0 (Andrew Jeffery 2019-11-08 15:49:39 +1030 554) {
9f4c2b516b4f0 (Andrew Jeffery 2019-11-08 15:49:39 +1030 555) unsigned long offset_unit, count_unit;
9f4c2b516b4f0 (Andrew Jeffery 2019-11-08 15:49:39 +1030 556)
9f4c2b516b4f0 (Andrew Jeffery 2019-11-08 15:49:39 +1030 557) /* Criteria:
9f4c2b516b4f0 (Andrew Jeffery 2019-11-08 15:49:39 +1030 558) *
9f4c2b516b4f0 (Andrew Jeffery 2019-11-08 15:49:39 +1030 559) * 1. Access size must be less than or equal to the maximum access
9f4c2b516b4f0 (Andrew Jeffery 2019-11-08 15:49:39 +1030 560) * width or the highest power-of-two factor of offset
9f4c2b516b4f0 (Andrew Jeffery 2019-11-08 15:49:39 +1030 561) * 2. Access size must be less than or equal to the amount specified by
9f4c2b516b4f0 (Andrew Jeffery 2019-11-08 15:49:39 +1030 562) * count
9f4c2b516b4f0 (Andrew Jeffery 2019-11-08 15:49:39 +1030 563) *
9f4c2b516b4f0 (Andrew Jeffery 2019-11-08 15:49:39 +1030 564) * The access width is optimal if we can calculate 1 to be strictly
9f4c2b516b4f0 (Andrew Jeffery 2019-11-08 15:49:39 +1030 565) * equal while still satisfying 2.
9f4c2b516b4f0 (Andrew Jeffery 2019-11-08 15:49:39 +1030 566) */
9f4c2b516b4f0 (Andrew Jeffery 2019-11-08 15:49:39 +1030 567)
9f4c2b516b4f0 (Andrew Jeffery 2019-11-08 15:49:39 +1030 568) /* Find 1 by the bottom bit of offset (with a 4 byte access cap) */
9f4c2b516b4f0 (Andrew Jeffery 2019-11-08 15:49:39 +1030 569) offset_unit = BIT(__builtin_ctzl(offset | 4));
9f4c2b516b4f0 (Andrew Jeffery 2019-11-08 15:49:39 +1030 570)
9f4c2b516b4f0 (Andrew Jeffery 2019-11-08 15:49:39 +1030 571) /* Find 2 by the top bit of count */
9f4c2b516b4f0 (Andrew Jeffery 2019-11-08 15:49:39 +1030 572) count_unit = BIT(8 * sizeof(unsigned long) - 1 - __builtin_clzl(count));
9f4c2b516b4f0 (Andrew Jeffery 2019-11-08 15:49:39 +1030 573)
9f4c2b516b4f0 (Andrew Jeffery 2019-11-08 15:49:39 +1030 574) /* Constrain the maximum access width to the minimum of both criteria */
9f4c2b516b4f0 (Andrew Jeffery 2019-11-08 15:49:39 +1030 575) return BIT(__builtin_ctzl(offset_unit | count_unit));
9f4c2b516b4f0 (Andrew Jeffery 2019-11-08 15:49:39 +1030 576) }
9f4c2b516b4f0 (Andrew Jeffery 2019-11-08 15:49:39 +1030 577)
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 578) static ssize_t fsi_slave_sysfs_raw_read(struct file *file,
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 579) struct kobject *kobj, struct bin_attribute *attr, char *buf,
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 580) loff_t off, size_t count)
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 581) {
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 582) struct fsi_slave *slave = to_fsi_slave(kobj_to_dev(kobj));
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 583) size_t total_len, read_len;
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 584) int rc;
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 585)
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 586) if (off < 0)
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 587) return -EINVAL;
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 588)
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 589) if (off > 0xffffffff || count > 0xffffffff || off + count > 0xffffffff)
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 590) return -EINVAL;
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 591)
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 592) for (total_len = 0; total_len < count; total_len += read_len) {
9f4c2b516b4f0 (Andrew Jeffery 2019-11-08 15:49:39 +1030 593) read_len = aligned_access_size(off, count - total_len);
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 594)
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 595) rc = fsi_slave_read(slave, off, buf + total_len, read_len);
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 596) if (rc)
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 597) return rc;
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 598)
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 599) off += read_len;
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 600) }
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 601)
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 602) return count;
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 603) }
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 604)
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 605) static ssize_t fsi_slave_sysfs_raw_write(struct file *file,
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 606) struct kobject *kobj, struct bin_attribute *attr,
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 607) char *buf, loff_t off, size_t count)
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 608) {
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 609) struct fsi_slave *slave = to_fsi_slave(kobj_to_dev(kobj));
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 610) size_t total_len, write_len;
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 611) int rc;
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 612)
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 613) if (off < 0)
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 614) return -EINVAL;
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 615)
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 616) if (off > 0xffffffff || count > 0xffffffff || off + count > 0xffffffff)
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 617) return -EINVAL;
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 618)
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 619) for (total_len = 0; total_len < count; total_len += write_len) {
9f4c2b516b4f0 (Andrew Jeffery 2019-11-08 15:49:39 +1030 620) write_len = aligned_access_size(off, count - total_len);
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 621)
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 622) rc = fsi_slave_write(slave, off, buf + total_len, write_len);
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 623) if (rc)
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 624) return rc;
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 625)
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 626) off += write_len;
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 627) }
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 628)
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 629) return count;
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 630) }
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 631)
061c0958de2e5 (Bhumika Goyal 2017-08-02 19:39:32 +0530 632) static const struct bin_attribute fsi_slave_raw_attr = {
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 633) .attr = {
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 634) .name = "raw",
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 635) .mode = 0600,
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 636) },
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 637) .size = 0,
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 638) .read = fsi_slave_sysfs_raw_read,
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 639) .write = fsi_slave_sysfs_raw_write,
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 640) };
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 641)
2b545cd8e1b2a (Jeremy Kerr 2017-06-06 16:08:42 -0500 642) static void fsi_slave_release(struct device *dev)
2b545cd8e1b2a (Jeremy Kerr 2017-06-06 16:08:42 -0500 643) {
2b545cd8e1b2a (Jeremy Kerr 2017-06-06 16:08:42 -0500 644) struct fsi_slave *slave = to_fsi_slave(dev);
2b545cd8e1b2a (Jeremy Kerr 2017-06-06 16:08:42 -0500 645)
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 646) fsi_free_minor(slave->dev.devt);
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 647) of_node_put(dev->of_node);
2b545cd8e1b2a (Jeremy Kerr 2017-06-06 16:08:42 -0500 648) kfree(slave);
2b545cd8e1b2a (Jeremy Kerr 2017-06-06 16:08:42 -0500 649) }
2b545cd8e1b2a (Jeremy Kerr 2017-06-06 16:08:42 -0500 650)
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 651) static bool fsi_slave_node_matches(struct device_node *np,
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 652) int link, uint8_t id)
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 653) {
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 654) unsigned int len, na, ns;
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 655) const __be32 *prop;
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 656)
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 657) na = of_n_addr_cells(np);
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 658) ns = of_n_size_cells(np);
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 659)
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 660) /* Ensure we have the correct format for addresses and sizes in
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 661) * reg properties
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 662) */
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 663) if (na != 2 || ns != 0)
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 664) return false;
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 665)
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 666) prop = of_get_property(np, "reg", &len);
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 667) if (!prop || len != 8)
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 668) return false;
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 669)
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 670) return (of_read_number(prop, 1) == link) &&
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 671) (of_read_number(prop + 1, 1) == id);
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 672) }
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 673)
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 674) /* Find a matching node for the slave at (link, id). Returns NULL if none
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 675) * found, or a matching node with refcount already incremented.
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 676) */
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 677) static struct device_node *fsi_slave_find_of_node(struct fsi_master *master,
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 678) int link, uint8_t id)
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 679) {
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 680) struct device_node *parent, *np;
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 681)
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 682) parent = dev_of_node(&master->dev);
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 683) if (!parent)
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 684) return NULL;
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 685)
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 686) for_each_child_of_node(parent, np) {
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 687) if (fsi_slave_node_matches(np, link, id))
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 688) return np;
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 689) }
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 690)
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 691) return NULL;
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 692) }
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 693)
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 694) static ssize_t cfam_read(struct file *filep, char __user *buf, size_t count,
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 695) loff_t *offset)
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 696) {
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 697) struct fsi_slave *slave = filep->private_data;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 698) size_t total_len, read_len;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 699) loff_t off = *offset;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 700) ssize_t rc;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 701)
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 702) if (off < 0)
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 703) return -EINVAL;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 704)
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 705) if (off > 0xffffffff || count > 0xffffffff || off + count > 0xffffffff)
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 706) return -EINVAL;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 707)
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 708) for (total_len = 0; total_len < count; total_len += read_len) {
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 709) __be32 data;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 710)
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 711) read_len = min_t(size_t, count, 4);
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 712) read_len -= off & 0x3;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 713)
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 714) rc = fsi_slave_read(slave, off, &data, read_len);
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 715) if (rc)
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 716) goto fail;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 717) rc = copy_to_user(buf + total_len, &data, read_len);
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 718) if (rc) {
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 719) rc = -EFAULT;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 720) goto fail;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 721) }
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 722) off += read_len;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 723) }
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 724) rc = count;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 725) fail:
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 726) *offset = off;
910810945707f (Colin Ian King 2021-06-03 13:28:12 +0100 727) return rc;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 728) }
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 729)
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 730) static ssize_t cfam_write(struct file *filep, const char __user *buf,
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 731) size_t count, loff_t *offset)
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 732) {
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 733) struct fsi_slave *slave = filep->private_data;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 734) size_t total_len, write_len;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 735) loff_t off = *offset;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 736) ssize_t rc;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 737)
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 738)
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 739) if (off < 0)
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 740) return -EINVAL;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 741)
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 742) if (off > 0xffffffff || count > 0xffffffff || off + count > 0xffffffff)
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 743) return -EINVAL;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 744)
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 745) for (total_len = 0; total_len < count; total_len += write_len) {
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 746) __be32 data;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 747)
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 748) write_len = min_t(size_t, count, 4);
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 749) write_len -= off & 0x3;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 750)
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 751) rc = copy_from_user(&data, buf + total_len, write_len);
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 752) if (rc) {
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 753) rc = -EFAULT;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 754) goto fail;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 755) }
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 756) rc = fsi_slave_write(slave, off, &data, write_len);
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 757) if (rc)
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 758) goto fail;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 759) off += write_len;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 760) }
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 761) rc = count;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 762) fail:
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 763) *offset = off;
910810945707f (Colin Ian King 2021-06-03 13:28:12 +0100 764) return rc;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 765) }
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 766)
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 767) static loff_t cfam_llseek(struct file *file, loff_t offset, int whence)
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 768) {
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 769) switch (whence) {
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 770) case SEEK_CUR:
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 771) break;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 772) case SEEK_SET:
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 773) file->f_pos = offset;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 774) break;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 775) default:
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 776) return -EINVAL;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 777) }
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 778)
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 779) return offset;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 780) }
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 781)
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 782) static int cfam_open(struct inode *inode, struct file *file)
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 783) {
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 784) struct fsi_slave *slave = container_of(inode->i_cdev, struct fsi_slave, cdev);
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 785)
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 786) file->private_data = slave;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 787)
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 788) return 0;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 789) }
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 790)
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 791) static const struct file_operations cfam_fops = {
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 792) .owner = THIS_MODULE,
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 793) .open = cfam_open,
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 794) .llseek = cfam_llseek,
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 795) .read = cfam_read,
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 796) .write = cfam_write,
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 797) };
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 798)
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 799) static ssize_t send_term_store(struct device *dev,
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 800) struct device_attribute *attr,
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 801) const char *buf, size_t count)
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 802) {
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 803) struct fsi_slave *slave = to_fsi_slave(dev);
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 804) struct fsi_master *master = slave->master;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 805)
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 806) if (!master->term)
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 807) return -ENODEV;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 808)
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 809) master->term(master, slave->link, slave->id);
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 810) return count;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 811) }
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 812)
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 813) static DEVICE_ATTR_WO(send_term);
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 814)
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 815) static ssize_t slave_send_echo_show(struct device *dev,
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 816) struct device_attribute *attr,
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 817) char *buf)
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 818) {
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 819) struct fsi_slave *slave = to_fsi_slave(dev);
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 820)
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 821) return sprintf(buf, "%u\n", slave->t_send_delay);
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 822) }
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 823)
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 824) static ssize_t slave_send_echo_store(struct device *dev,
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 825) struct device_attribute *attr, const char *buf, size_t count)
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 826) {
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 827) struct fsi_slave *slave = to_fsi_slave(dev);
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 828) struct fsi_master *master = slave->master;
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 829) unsigned long val;
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 830) int rc;
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 831)
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 832) if (kstrtoul(buf, 0, &val) < 0)
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 833) return -EINVAL;
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 834)
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 835) if (val < 1 || val > 16)
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 836) return -EINVAL;
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 837)
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 838) if (!master->link_config)
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 839) return -ENXIO;
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 840)
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 841) /* Current HW mandates that send and echo delay are identical */
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 842) slave->t_send_delay = val;
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 843) slave->t_echo_delay = val;
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 844)
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 845) rc = fsi_slave_set_smode(slave);
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 846) if (rc < 0)
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 847) return rc;
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 848) if (master->link_config)
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 849) master->link_config(master, slave->link,
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 850) slave->t_send_delay,
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 851) slave->t_echo_delay);
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 852)
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 853) return count;
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 854) }
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 855)
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 856) static DEVICE_ATTR(send_echo_delays, 0600,
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 857) slave_send_echo_show, slave_send_echo_store);
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 858)
0a213777d1dd8 (Benjamin Herrenschmidt 2018-06-20 15:16:31 +1000 859) static ssize_t chip_id_show(struct device *dev,
0a213777d1dd8 (Benjamin Herrenschmidt 2018-06-20 15:16:31 +1000 860) struct device_attribute *attr,
0a213777d1dd8 (Benjamin Herrenschmidt 2018-06-20 15:16:31 +1000 861) char *buf)
0a213777d1dd8 (Benjamin Herrenschmidt 2018-06-20 15:16:31 +1000 862) {
0a213777d1dd8 (Benjamin Herrenschmidt 2018-06-20 15:16:31 +1000 863) struct fsi_slave *slave = to_fsi_slave(dev);
0a213777d1dd8 (Benjamin Herrenschmidt 2018-06-20 15:16:31 +1000 864)
0a213777d1dd8 (Benjamin Herrenschmidt 2018-06-20 15:16:31 +1000 865) return sprintf(buf, "%d\n", slave->chip_id);
0a213777d1dd8 (Benjamin Herrenschmidt 2018-06-20 15:16:31 +1000 866) }
0a213777d1dd8 (Benjamin Herrenschmidt 2018-06-20 15:16:31 +1000 867)
0a213777d1dd8 (Benjamin Herrenschmidt 2018-06-20 15:16:31 +1000 868) static DEVICE_ATTR_RO(chip_id);
0a213777d1dd8 (Benjamin Herrenschmidt 2018-06-20 15:16:31 +1000 869)
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 870) static ssize_t cfam_id_show(struct device *dev,
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 871) struct device_attribute *attr,
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 872) char *buf)
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 873) {
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 874) struct fsi_slave *slave = to_fsi_slave(dev);
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 875)
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 876) return sprintf(buf, "0x%x\n", slave->cfam_id);
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 877) }
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 878)
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 879) static DEVICE_ATTR_RO(cfam_id);
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 880)
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 881) static struct attribute *cfam_attr[] = {
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 882) &dev_attr_send_echo_delays.attr,
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 883) &dev_attr_chip_id.attr,
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 884) &dev_attr_cfam_id.attr,
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 885) &dev_attr_send_term.attr,
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 886) NULL,
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 887) };
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 888)
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 889) static const struct attribute_group cfam_attr_group = {
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 890) .attrs = cfam_attr,
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 891) };
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 892)
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 893) static const struct attribute_group *cfam_attr_groups[] = {
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 894) &cfam_attr_group,
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 895) NULL,
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 896) };
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 897)
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 898) static char *cfam_devnode(struct device *dev, umode_t *mode,
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 899) kuid_t *uid, kgid_t *gid)
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 900) {
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 901) struct fsi_slave *slave = to_fsi_slave(dev);
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 902)
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 903) #ifdef CONFIG_FSI_NEW_DEV_NODE
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 904) return kasprintf(GFP_KERNEL, "fsi/cfam%d", slave->cdev_idx);
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 905) #else
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 906) return kasprintf(GFP_KERNEL, "cfam%d", slave->cdev_idx);
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 907) #endif
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 908) }
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 909)
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 910) static const struct device_type cfam_type = {
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 911) .name = "cfam",
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 912) .devnode = cfam_devnode,
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 913) .groups = cfam_attr_groups
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 914) };
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 915)
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 916) static char *fsi_cdev_devnode(struct device *dev, umode_t *mode,
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 917) kuid_t *uid, kgid_t *gid)
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 918) {
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 919) #ifdef CONFIG_FSI_NEW_DEV_NODE
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 920) return kasprintf(GFP_KERNEL, "fsi/%s", dev_name(dev));
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 921) #else
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 922) return kasprintf(GFP_KERNEL, "%s", dev_name(dev));
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 923) #endif
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 924) }
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 925)
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 926) const struct device_type fsi_cdev_type = {
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 927) .name = "fsi-cdev",
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 928) .devnode = fsi_cdev_devnode,
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 929) };
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 930) EXPORT_SYMBOL_GPL(fsi_cdev_type);
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 931)
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 932) /* Backward compatible /dev/ numbering in "old style" mode */
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 933) static int fsi_adjust_index(int index)
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 934) {
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 935) #ifdef CONFIG_FSI_NEW_DEV_NODE
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 936) return index;
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 937) #else
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 938) return index + 1;
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 939) #endif
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 940) }
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 941)
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 942) static int __fsi_get_new_minor(struct fsi_slave *slave, enum fsi_dev_type type,
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 943) dev_t *out_dev, int *out_index)
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 944) {
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 945) int cid = slave->chip_id;
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 946) int id;
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 947)
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 948) /* Check if we qualify for legacy numbering */
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 949) if (cid >= 0 && cid < 16 && type < 4) {
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 950) /* Try reserving the legacy number */
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 951) id = (cid << 4) | type;
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 952) id = ida_simple_get(&fsi_minor_ida, id, id + 1, GFP_KERNEL);
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 953) if (id >= 0) {
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 954) *out_index = fsi_adjust_index(cid);
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 955) *out_dev = fsi_base_dev + id;
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 956) return 0;
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 957) }
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 958) /* Other failure */
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 959) if (id != -ENOSPC)
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 960) return id;
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 961) /* Fallback to non-legacy allocation */
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 962) }
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 963) id = ida_simple_get(&fsi_minor_ida, FSI_CHAR_LEGACY_TOP,
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 964) FSI_CHAR_MAX_DEVICES, GFP_KERNEL);
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 965) if (id < 0)
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 966) return id;
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 967) *out_index = fsi_adjust_index(id);
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 968) *out_dev = fsi_base_dev + id;
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 969) return 0;
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 970) }
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 971)
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 972) int fsi_get_new_minor(struct fsi_device *fdev, enum fsi_dev_type type,
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 973) dev_t *out_dev, int *out_index)
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 974) {
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 975) return __fsi_get_new_minor(fdev->slave, type, out_dev, out_index);
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 976) }
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 977) EXPORT_SYMBOL_GPL(fsi_get_new_minor);
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 978)
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 979) void fsi_free_minor(dev_t dev)
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 980) {
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 981) ida_simple_remove(&fsi_minor_ida, MINOR(dev));
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 982) }
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 983) EXPORT_SYMBOL_GPL(fsi_free_minor);
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 984)
414c1026319bc (Jeremy Kerr 2017-06-06 16:08:38 -0500 985) static int fsi_slave_init(struct fsi_master *master, int link, uint8_t id)
414c1026319bc (Jeremy Kerr 2017-06-06 16:08:38 -0500 986) {
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 987) uint32_t cfam_id;
2b545cd8e1b2a (Jeremy Kerr 2017-06-06 16:08:42 -0500 988) struct fsi_slave *slave;
2b545cd8e1b2a (Jeremy Kerr 2017-06-06 16:08:42 -0500 989) uint8_t crc;
196964a31cf8c (Eddie James 2020-05-20 13:17:07 -0500 990) __be32 data, llmode, slbus;
2b545cd8e1b2a (Jeremy Kerr 2017-06-06 16:08:42 -0500 991) int rc;
2b545cd8e1b2a (Jeremy Kerr 2017-06-06 16:08:42 -0500 992)
2b545cd8e1b2a (Jeremy Kerr 2017-06-06 16:08:42 -0500 993) /* Currently, we only support single slaves on a link, and use the
2b545cd8e1b2a (Jeremy Kerr 2017-06-06 16:08:42 -0500 994) * full 23-bit address range
2b545cd8e1b2a (Jeremy Kerr 2017-06-06 16:08:42 -0500 995) */
2b545cd8e1b2a (Jeremy Kerr 2017-06-06 16:08:42 -0500 996) if (id != 0)
2b545cd8e1b2a (Jeremy Kerr 2017-06-06 16:08:42 -0500 997) return -EINVAL;
2b545cd8e1b2a (Jeremy Kerr 2017-06-06 16:08:42 -0500 998)
11454d6dc8181 (Joel Stanley 2018-06-18 13:13:35 +0930 999) rc = fsi_master_read(master, link, id, 0, &data, sizeof(data));
2b545cd8e1b2a (Jeremy Kerr 2017-06-06 16:08:42 -0500 1000) if (rc) {
2b545cd8e1b2a (Jeremy Kerr 2017-06-06 16:08:42 -0500 1001) dev_dbg(&master->dev, "can't read slave %02x:%02x %d\n",
2b545cd8e1b2a (Jeremy Kerr 2017-06-06 16:08:42 -0500 1002) link, id, rc);
2b545cd8e1b2a (Jeremy Kerr 2017-06-06 16:08:42 -0500 1003) return -ENODEV;
2b545cd8e1b2a (Jeremy Kerr 2017-06-06 16:08:42 -0500 1004) }
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 1005) cfam_id = be32_to_cpu(data);
2b545cd8e1b2a (Jeremy Kerr 2017-06-06 16:08:42 -0500 1006)
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 1007) crc = crc4(0, cfam_id, 32);
2b545cd8e1b2a (Jeremy Kerr 2017-06-06 16:08:42 -0500 1008) if (crc) {
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 1009) dev_warn(&master->dev, "slave %02x:%02x invalid cfam id CRC!\n",
2b545cd8e1b2a (Jeremy Kerr 2017-06-06 16:08:42 -0500 1010) link, id);
2b545cd8e1b2a (Jeremy Kerr 2017-06-06 16:08:42 -0500 1011) return -EIO;
2b545cd8e1b2a (Jeremy Kerr 2017-06-06 16:08:42 -0500 1012) }
2b545cd8e1b2a (Jeremy Kerr 2017-06-06 16:08:42 -0500 1013)
638bd9ac847e8 (Christopher Bostic 2018-02-12 15:45:46 +1030 1014) dev_dbg(&master->dev, "fsi: found chip %08x at %02x:%02x:%02x\n",
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 1015) cfam_id, master->idx, link, id);
2b545cd8e1b2a (Jeremy Kerr 2017-06-06 16:08:42 -0500 1016)
4af889b0ff78a (Jeremy Kerr 2017-06-06 16:08:58 -0500 1017) /* If we're behind a master that doesn't provide a self-running bus
4af889b0ff78a (Jeremy Kerr 2017-06-06 16:08:58 -0500 1018) * clock, put the slave into async mode
4af889b0ff78a (Jeremy Kerr 2017-06-06 16:08:58 -0500 1019) */
4af889b0ff78a (Jeremy Kerr 2017-06-06 16:08:58 -0500 1020) if (master->flags & FSI_MASTER_FLAG_SWCLOCK) {
4af889b0ff78a (Jeremy Kerr 2017-06-06 16:08:58 -0500 1021) llmode = cpu_to_be32(FSI_LLMODE_ASYNC);
4af889b0ff78a (Jeremy Kerr 2017-06-06 16:08:58 -0500 1022) rc = fsi_master_write(master, link, id,
4af889b0ff78a (Jeremy Kerr 2017-06-06 16:08:58 -0500 1023) FSI_SLAVE_BASE + FSI_LLMODE,
4af889b0ff78a (Jeremy Kerr 2017-06-06 16:08:58 -0500 1024) &llmode, sizeof(llmode));
4af889b0ff78a (Jeremy Kerr 2017-06-06 16:08:58 -0500 1025) if (rc)
4af889b0ff78a (Jeremy Kerr 2017-06-06 16:08:58 -0500 1026) dev_warn(&master->dev,
4af889b0ff78a (Jeremy Kerr 2017-06-06 16:08:58 -0500 1027) "can't set llmode on slave:%02x:%02x %d\n",
4af889b0ff78a (Jeremy Kerr 2017-06-06 16:08:58 -0500 1028) link, id, rc);
4af889b0ff78a (Jeremy Kerr 2017-06-06 16:08:58 -0500 1029) }
4af889b0ff78a (Jeremy Kerr 2017-06-06 16:08:58 -0500 1030)
2b545cd8e1b2a (Jeremy Kerr 2017-06-06 16:08:42 -0500 1031) /* We can communicate with a slave; create the slave device and
2b545cd8e1b2a (Jeremy Kerr 2017-06-06 16:08:42 -0500 1032) * register.
2b545cd8e1b2a (Jeremy Kerr 2017-06-06 16:08:42 -0500 1033) */
2b545cd8e1b2a (Jeremy Kerr 2017-06-06 16:08:42 -0500 1034) slave = kzalloc(sizeof(*slave), GFP_KERNEL);
2b545cd8e1b2a (Jeremy Kerr 2017-06-06 16:08:42 -0500 1035) if (!slave)
2b545cd8e1b2a (Jeremy Kerr 2017-06-06 16:08:42 -0500 1036) return -ENOMEM;
2b545cd8e1b2a (Jeremy Kerr 2017-06-06 16:08:42 -0500 1037)
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 1038) dev_set_name(&slave->dev, "slave@%02x:%02x", link, id);
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 1039) slave->dev.type = &cfam_type;
2b545cd8e1b2a (Jeremy Kerr 2017-06-06 16:08:42 -0500 1040) slave->dev.parent = &master->dev;
f6a2f8eb73f0d (Jeremy Kerr 2018-02-12 15:45:45 +1030 1041) slave->dev.of_node = fsi_slave_find_of_node(master, link, id);
2b545cd8e1b2a (Jeremy Kerr 2017-06-06 16:08:42 -0500 1042) slave->dev.release = fsi_slave_release;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 1043) device_initialize(&slave->dev);
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 1044) slave->cfam_id = cfam_id;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 1045) slave->master = master;
2b545cd8e1b2a (Jeremy Kerr 2017-06-06 16:08:42 -0500 1046) slave->link = link;
2b545cd8e1b2a (Jeremy Kerr 2017-06-06 16:08:42 -0500 1047) slave->id = id;
2b545cd8e1b2a (Jeremy Kerr 2017-06-06 16:08:42 -0500 1048) slave->size = FSI_SLAVE_SIZE_23b;
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 1049) slave->t_send_delay = 16;
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 1050) slave->t_echo_delay = 16;
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 1051)
0a213777d1dd8 (Benjamin Herrenschmidt 2018-06-20 15:16:31 +1000 1052) /* Get chip ID if any */
0a213777d1dd8 (Benjamin Herrenschmidt 2018-06-20 15:16:31 +1000 1053) slave->chip_id = -1;
0a213777d1dd8 (Benjamin Herrenschmidt 2018-06-20 15:16:31 +1000 1054) if (slave->dev.of_node) {
0a213777d1dd8 (Benjamin Herrenschmidt 2018-06-20 15:16:31 +1000 1055) uint32_t prop;
0a213777d1dd8 (Benjamin Herrenschmidt 2018-06-20 15:16:31 +1000 1056) if (!of_property_read_u32(slave->dev.of_node, "chip-id", &prop))
0a213777d1dd8 (Benjamin Herrenschmidt 2018-06-20 15:16:31 +1000 1057) slave->chip_id = prop;
0a213777d1dd8 (Benjamin Herrenschmidt 2018-06-20 15:16:31 +1000 1058)
0a213777d1dd8 (Benjamin Herrenschmidt 2018-06-20 15:16:31 +1000 1059) }
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 1060)
196964a31cf8c (Eddie James 2020-05-20 13:17:07 -0500 1061) slbus = cpu_to_be32(FSI_SLBUS_FORCE);
196964a31cf8c (Eddie James 2020-05-20 13:17:07 -0500 1062) rc = fsi_master_write(master, link, id, FSI_SLAVE_BASE + FSI_SLBUS,
196964a31cf8c (Eddie James 2020-05-20 13:17:07 -0500 1063) &slbus, sizeof(slbus));
196964a31cf8c (Eddie James 2020-05-20 13:17:07 -0500 1064) if (rc)
196964a31cf8c (Eddie James 2020-05-20 13:17:07 -0500 1065) dev_warn(&master->dev,
196964a31cf8c (Eddie James 2020-05-20 13:17:07 -0500 1066) "can't set slbus on slave:%02x:%02x %d\n", link, id,
196964a31cf8c (Eddie James 2020-05-20 13:17:07 -0500 1067) rc);
196964a31cf8c (Eddie James 2020-05-20 13:17:07 -0500 1068)
371975b0b0752 (Jeremy Kerr 2019-06-28 16:07:37 +0800 1069) rc = fsi_slave_set_smode(slave);
371975b0b0752 (Jeremy Kerr 2019-06-28 16:07:37 +0800 1070) if (rc) {
371975b0b0752 (Jeremy Kerr 2019-06-28 16:07:37 +0800 1071) dev_warn(&master->dev,
371975b0b0752 (Jeremy Kerr 2019-06-28 16:07:37 +0800 1072) "can't set smode on slave:%02x:%02x %d\n",
371975b0b0752 (Jeremy Kerr 2019-06-28 16:07:37 +0800 1073) link, id, rc);
371975b0b0752 (Jeremy Kerr 2019-06-28 16:07:37 +0800 1074) goto err_free;
371975b0b0752 (Jeremy Kerr 2019-06-28 16:07:37 +0800 1075) }
371975b0b0752 (Jeremy Kerr 2019-06-28 16:07:37 +0800 1076)
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 1077) /* Allocate a minor in the FSI space */
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 1078) rc = __fsi_get_new_minor(slave, fsi_dev_cfam, &slave->dev.devt,
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 1079) &slave->cdev_idx);
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 1080) if (rc)
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 1081) goto err_free;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 1082)
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 1083) /* Create chardev for userspace access */
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 1084) cdev_init(&slave->cdev, &cfam_fops);
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 1085) rc = cdev_device_add(&slave->cdev, &slave->dev);
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 1086) if (rc) {
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 1087) dev_err(&slave->dev, "Error %d creating slave device\n", rc);
371975b0b0752 (Jeremy Kerr 2019-06-28 16:07:37 +0800 1088) goto err_free_ida;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 1089) }
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 1090)
371975b0b0752 (Jeremy Kerr 2019-06-28 16:07:37 +0800 1091) /* Now that we have the cdev registered with the core, any fatal
371975b0b0752 (Jeremy Kerr 2019-06-28 16:07:37 +0800 1092) * failures beyond this point will need to clean up through
371975b0b0752 (Jeremy Kerr 2019-06-28 16:07:37 +0800 1093) * cdev_device_del(). Fortunately though, nothing past here is fatal.
371975b0b0752 (Jeremy Kerr 2019-06-28 16:07:37 +0800 1094) */
371975b0b0752 (Jeremy Kerr 2019-06-28 16:07:37 +0800 1095)
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 1096) if (master->link_config)
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 1097) master->link_config(master, link,
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 1098) slave->t_send_delay,
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 1099) slave->t_echo_delay);
2b545cd8e1b2a (Jeremy Kerr 2017-06-06 16:08:42 -0500 1100)
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 1101) /* Legacy raw file -> to be removed */
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 1102) rc = device_create_bin_file(&slave->dev, &fsi_slave_raw_attr);
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 1103) if (rc)
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 1104) dev_warn(&slave->dev, "failed to create raw attr: %d\n", rc);
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 1105)
0a213777d1dd8 (Benjamin Herrenschmidt 2018-06-20 15:16:31 +1000 1106)
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 1107) rc = fsi_slave_scan(slave);
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 1108) if (rc)
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 1109) dev_dbg(&master->dev, "failed during slave scan with: %d\n",
f7ade2a603cfd (Jeremy Kerr 2017-06-06 16:08:44 -0500 1110) rc);
414c1026319bc (Jeremy Kerr 2017-06-06 16:08:38 -0500 1111)
371975b0b0752 (Jeremy Kerr 2019-06-28 16:07:37 +0800 1112) return 0;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 1113)
371975b0b0752 (Jeremy Kerr 2019-06-28 16:07:37 +0800 1114) err_free_ida:
371975b0b0752 (Jeremy Kerr 2019-06-28 16:07:37 +0800 1115) fsi_free_minor(slave->dev.devt);
371975b0b0752 (Jeremy Kerr 2019-06-28 16:07:37 +0800 1116) err_free:
371975b0b0752 (Jeremy Kerr 2019-06-28 16:07:37 +0800 1117) of_node_put(slave->dev.of_node);
371975b0b0752 (Jeremy Kerr 2019-06-28 16:07:37 +0800 1118) kfree(slave);
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 1119) return rc;
414c1026319bc (Jeremy Kerr 2017-06-06 16:08:38 -0500 1120) }
414c1026319bc (Jeremy Kerr 2017-06-06 16:08:38 -0500 1121)
09aecfab93b8f (Jeremy Kerr 2017-06-06 16:08:36 -0500 1122) /* FSI master support */
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 1123) static int fsi_check_access(uint32_t addr, size_t size)
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 1124) {
99f039e97bf8a (Eddie James 2018-02-12 15:45:43 +1030 1125) if (size == 4) {
99f039e97bf8a (Eddie James 2018-02-12 15:45:43 +1030 1126) if (addr & 0x3)
99f039e97bf8a (Eddie James 2018-02-12 15:45:43 +1030 1127) return -EINVAL;
99f039e97bf8a (Eddie James 2018-02-12 15:45:43 +1030 1128) } else if (size == 2) {
99f039e97bf8a (Eddie James 2018-02-12 15:45:43 +1030 1129) if (addr & 0x1)
99f039e97bf8a (Eddie James 2018-02-12 15:45:43 +1030 1130) return -EINVAL;
99f039e97bf8a (Eddie James 2018-02-12 15:45:43 +1030 1131) } else if (size != 1)
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 1132) return -EINVAL;
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 1133)
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 1134) return 0;
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 1135) }
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 1136)
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 1137) static int fsi_master_read(struct fsi_master *master, int link,
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 1138) uint8_t slave_id, uint32_t addr, void *val, size_t size)
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 1139) {
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 1140) int rc;
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 1141)
66433b05a3b2b (Jeremy Kerr 2017-06-06 16:08:51 -0500 1142) trace_fsi_master_read(master, link, slave_id, addr, size);
66433b05a3b2b (Jeremy Kerr 2017-06-06 16:08:51 -0500 1143)
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 1144) rc = fsi_check_access(addr, size);
66433b05a3b2b (Jeremy Kerr 2017-06-06 16:08:51 -0500 1145) if (!rc)
66433b05a3b2b (Jeremy Kerr 2017-06-06 16:08:51 -0500 1146) rc = master->read(master, link, slave_id, addr, val, size);
66433b05a3b2b (Jeremy Kerr 2017-06-06 16:08:51 -0500 1147)
66433b05a3b2b (Jeremy Kerr 2017-06-06 16:08:51 -0500 1148) trace_fsi_master_rw_result(master, link, slave_id, addr, size,
66433b05a3b2b (Jeremy Kerr 2017-06-06 16:08:51 -0500 1149) false, val, rc);
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 1150)
66433b05a3b2b (Jeremy Kerr 2017-06-06 16:08:51 -0500 1151) return rc;
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 1152) }
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 1153)
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 1154) static int fsi_master_write(struct fsi_master *master, int link,
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 1155) uint8_t slave_id, uint32_t addr, const void *val, size_t size)
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 1156) {
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 1157) int rc;
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 1158)
66433b05a3b2b (Jeremy Kerr 2017-06-06 16:08:51 -0500 1159) trace_fsi_master_write(master, link, slave_id, addr, size, val);
66433b05a3b2b (Jeremy Kerr 2017-06-06 16:08:51 -0500 1160)
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 1161) rc = fsi_check_access(addr, size);
66433b05a3b2b (Jeremy Kerr 2017-06-06 16:08:51 -0500 1162) if (!rc)
66433b05a3b2b (Jeremy Kerr 2017-06-06 16:08:51 -0500 1163) rc = master->write(master, link, slave_id, addr, val, size);
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 1164)
66433b05a3b2b (Jeremy Kerr 2017-06-06 16:08:51 -0500 1165) trace_fsi_master_rw_result(master, link, slave_id, addr, size,
66433b05a3b2b (Jeremy Kerr 2017-06-06 16:08:51 -0500 1166) true, val, rc);
66433b05a3b2b (Jeremy Kerr 2017-06-06 16:08:51 -0500 1167)
66433b05a3b2b (Jeremy Kerr 2017-06-06 16:08:51 -0500 1168) return rc;
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 1169) }
014c2abc530d7 (Jeremy Kerr 2017-06-06 16:08:40 -0500 1170)
b36875a453ef8 (Eddie James 2020-06-09 16:39:28 -0500 1171) static int fsi_master_link_disable(struct fsi_master *master, int link)
b36875a453ef8 (Eddie James 2020-06-09 16:39:28 -0500 1172) {
b36875a453ef8 (Eddie James 2020-06-09 16:39:28 -0500 1173) if (master->link_enable)
b36875a453ef8 (Eddie James 2020-06-09 16:39:28 -0500 1174) return master->link_enable(master, link, false);
b36875a453ef8 (Eddie James 2020-06-09 16:39:28 -0500 1175)
b36875a453ef8 (Eddie James 2020-06-09 16:39:28 -0500 1176) return 0;
b36875a453ef8 (Eddie James 2020-06-09 16:39:28 -0500 1177) }
b36875a453ef8 (Eddie James 2020-06-09 16:39:28 -0500 1178)
26095282119ec (Christopher Bostic 2017-06-06 16:08:41 -0500 1179) static int fsi_master_link_enable(struct fsi_master *master, int link)
26095282119ec (Christopher Bostic 2017-06-06 16:08:41 -0500 1180) {
26095282119ec (Christopher Bostic 2017-06-06 16:08:41 -0500 1181) if (master->link_enable)
04635a30dd538 (Eddie James 2020-06-09 16:39:27 -0500 1182) return master->link_enable(master, link, true);
26095282119ec (Christopher Bostic 2017-06-06 16:08:41 -0500 1183)
26095282119ec (Christopher Bostic 2017-06-06 16:08:41 -0500 1184) return 0;
26095282119ec (Christopher Bostic 2017-06-06 16:08:41 -0500 1185) }
26095282119ec (Christopher Bostic 2017-06-06 16:08:41 -0500 1186)
26095282119ec (Christopher Bostic 2017-06-06 16:08:41 -0500 1187) /*
26095282119ec (Christopher Bostic 2017-06-06 16:08:41 -0500 1188) * Issue a break command on this link
26095282119ec (Christopher Bostic 2017-06-06 16:08:41 -0500 1189) */
26095282119ec (Christopher Bostic 2017-06-06 16:08:41 -0500 1190) static int fsi_master_break(struct fsi_master *master, int link)
26095282119ec (Christopher Bostic 2017-06-06 16:08:41 -0500 1191) {
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 1192) int rc = 0;
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 1193)
66433b05a3b2b (Jeremy Kerr 2017-06-06 16:08:51 -0500 1194) trace_fsi_master_break(master, link);
66433b05a3b2b (Jeremy Kerr 2017-06-06 16:08:51 -0500 1195)
26095282119ec (Christopher Bostic 2017-06-06 16:08:41 -0500 1196) if (master->send_break)
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 1197) rc = master->send_break(master, link);
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 1198) if (master->link_config)
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 1199) master->link_config(master, link, 16, 16);
26095282119ec (Christopher Bostic 2017-06-06 16:08:41 -0500 1200)
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 1201) return rc;
26095282119ec (Christopher Bostic 2017-06-06 16:08:41 -0500 1202) }
26095282119ec (Christopher Bostic 2017-06-06 16:08:41 -0500 1203)
414c1026319bc (Jeremy Kerr 2017-06-06 16:08:38 -0500 1204) static int fsi_master_scan(struct fsi_master *master)
414c1026319bc (Jeremy Kerr 2017-06-06 16:08:38 -0500 1205) {
26095282119ec (Christopher Bostic 2017-06-06 16:08:41 -0500 1206) int link, rc;
26095282119ec (Christopher Bostic 2017-06-06 16:08:41 -0500 1207)
26095282119ec (Christopher Bostic 2017-06-06 16:08:41 -0500 1208) for (link = 0; link < master->n_links; link++) {
26095282119ec (Christopher Bostic 2017-06-06 16:08:41 -0500 1209) rc = fsi_master_link_enable(master, link);
26095282119ec (Christopher Bostic 2017-06-06 16:08:41 -0500 1210) if (rc) {
26095282119ec (Christopher Bostic 2017-06-06 16:08:41 -0500 1211) dev_dbg(&master->dev,
26095282119ec (Christopher Bostic 2017-06-06 16:08:41 -0500 1212) "enable link %d failed: %d\n", link, rc);
26095282119ec (Christopher Bostic 2017-06-06 16:08:41 -0500 1213) continue;
26095282119ec (Christopher Bostic 2017-06-06 16:08:41 -0500 1214) }
26095282119ec (Christopher Bostic 2017-06-06 16:08:41 -0500 1215) rc = fsi_master_break(master, link);
26095282119ec (Christopher Bostic 2017-06-06 16:08:41 -0500 1216) if (rc) {
b36875a453ef8 (Eddie James 2020-06-09 16:39:28 -0500 1217) fsi_master_link_disable(master, link);
26095282119ec (Christopher Bostic 2017-06-06 16:08:41 -0500 1218) dev_dbg(&master->dev,
26095282119ec (Christopher Bostic 2017-06-06 16:08:41 -0500 1219) "break to link %d failed: %d\n", link, rc);
26095282119ec (Christopher Bostic 2017-06-06 16:08:41 -0500 1220) continue;
26095282119ec (Christopher Bostic 2017-06-06 16:08:41 -0500 1221) }
414c1026319bc (Jeremy Kerr 2017-06-06 16:08:38 -0500 1222)
b36875a453ef8 (Eddie James 2020-06-09 16:39:28 -0500 1223) rc = fsi_slave_init(master, link, 0);
b36875a453ef8 (Eddie James 2020-06-09 16:39:28 -0500 1224) if (rc)
b36875a453ef8 (Eddie James 2020-06-09 16:39:28 -0500 1225) fsi_master_link_disable(master, link);
26095282119ec (Christopher Bostic 2017-06-06 16:08:41 -0500 1226) }
414c1026319bc (Jeremy Kerr 2017-06-06 16:08:38 -0500 1227)
414c1026319bc (Jeremy Kerr 2017-06-06 16:08:38 -0500 1228) return 0;
414c1026319bc (Jeremy Kerr 2017-06-06 16:08:38 -0500 1229) }
414c1026319bc (Jeremy Kerr 2017-06-06 16:08:38 -0500 1230)
cd0fdb5c07b27 (Christopher Bostic 2017-06-06 16:08:46 -0500 1231) static int fsi_slave_remove_device(struct device *dev, void *arg)
cd0fdb5c07b27 (Christopher Bostic 2017-06-06 16:08:46 -0500 1232) {
cd0fdb5c07b27 (Christopher Bostic 2017-06-06 16:08:46 -0500 1233) device_unregister(dev);
cd0fdb5c07b27 (Christopher Bostic 2017-06-06 16:08:46 -0500 1234) return 0;
cd0fdb5c07b27 (Christopher Bostic 2017-06-06 16:08:46 -0500 1235) }
cd0fdb5c07b27 (Christopher Bostic 2017-06-06 16:08:46 -0500 1236)
cd0fdb5c07b27 (Christopher Bostic 2017-06-06 16:08:46 -0500 1237) static int fsi_master_remove_slave(struct device *dev, void *arg)
cd0fdb5c07b27 (Christopher Bostic 2017-06-06 16:08:46 -0500 1238) {
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 1239) struct fsi_slave *slave = to_fsi_slave(dev);
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 1240)
cd0fdb5c07b27 (Christopher Bostic 2017-06-06 16:08:46 -0500 1241) device_for_each_child(dev, NULL, fsi_slave_remove_device);
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 1242) cdev_device_del(&slave->cdev, &slave->dev);
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 1243) put_device(dev);
cd0fdb5c07b27 (Christopher Bostic 2017-06-06 16:08:46 -0500 1244) return 0;
cd0fdb5c07b27 (Christopher Bostic 2017-06-06 16:08:46 -0500 1245) }
cd0fdb5c07b27 (Christopher Bostic 2017-06-06 16:08:46 -0500 1246)
cd0fdb5c07b27 (Christopher Bostic 2017-06-06 16:08:46 -0500 1247) static void fsi_master_unscan(struct fsi_master *master)
cd0fdb5c07b27 (Christopher Bostic 2017-06-06 16:08:46 -0500 1248) {
cd0fdb5c07b27 (Christopher Bostic 2017-06-06 16:08:46 -0500 1249) device_for_each_child(&master->dev, NULL, fsi_master_remove_slave);
cd0fdb5c07b27 (Christopher Bostic 2017-06-06 16:08:46 -0500 1250) }
cd0fdb5c07b27 (Christopher Bostic 2017-06-06 16:08:46 -0500 1251)
15362d69c4c88 (Jeremy Kerr 2018-02-12 15:45:40 +1030 1252) int fsi_master_rescan(struct fsi_master *master)
15362d69c4c88 (Jeremy Kerr 2018-02-12 15:45:40 +1030 1253) {
9840fcd8cc43b (Benjamin Herrenschmidt 2018-06-21 18:00:05 +1000 1254) int rc;
9840fcd8cc43b (Benjamin Herrenschmidt 2018-06-21 18:00:05 +1000 1255)
9840fcd8cc43b (Benjamin Herrenschmidt 2018-06-21 18:00:05 +1000 1256) mutex_lock(&master->scan_lock);
15362d69c4c88 (Jeremy Kerr 2018-02-12 15:45:40 +1030 1257) fsi_master_unscan(master);
9840fcd8cc43b (Benjamin Herrenschmidt 2018-06-21 18:00:05 +1000 1258) rc = fsi_master_scan(master);
9840fcd8cc43b (Benjamin Herrenschmidt 2018-06-21 18:00:05 +1000 1259) mutex_unlock(&master->scan_lock);
9840fcd8cc43b (Benjamin Herrenschmidt 2018-06-21 18:00:05 +1000 1260)
9840fcd8cc43b (Benjamin Herrenschmidt 2018-06-21 18:00:05 +1000 1261) return rc;
15362d69c4c88 (Jeremy Kerr 2018-02-12 15:45:40 +1030 1262) }
15362d69c4c88 (Jeremy Kerr 2018-02-12 15:45:40 +1030 1263) EXPORT_SYMBOL_GPL(fsi_master_rescan);
15362d69c4c88 (Jeremy Kerr 2018-02-12 15:45:40 +1030 1264)
cd0fdb5c07b27 (Christopher Bostic 2017-06-06 16:08:46 -0500 1265) static ssize_t master_rescan_store(struct device *dev,
cd0fdb5c07b27 (Christopher Bostic 2017-06-06 16:08:46 -0500 1266) struct device_attribute *attr, const char *buf, size_t count)
cd0fdb5c07b27 (Christopher Bostic 2017-06-06 16:08:46 -0500 1267) {
cd0fdb5c07b27 (Christopher Bostic 2017-06-06 16:08:46 -0500 1268) struct fsi_master *master = to_fsi_master(dev);
cd0fdb5c07b27 (Christopher Bostic 2017-06-06 16:08:46 -0500 1269) int rc;
cd0fdb5c07b27 (Christopher Bostic 2017-06-06 16:08:46 -0500 1270)
15362d69c4c88 (Jeremy Kerr 2018-02-12 15:45:40 +1030 1271) rc = fsi_master_rescan(master);
cd0fdb5c07b27 (Christopher Bostic 2017-06-06 16:08:46 -0500 1272) if (rc < 0)
cd0fdb5c07b27 (Christopher Bostic 2017-06-06 16:08:46 -0500 1273) return rc;
cd0fdb5c07b27 (Christopher Bostic 2017-06-06 16:08:46 -0500 1274)
cd0fdb5c07b27 (Christopher Bostic 2017-06-06 16:08:46 -0500 1275) return count;
cd0fdb5c07b27 (Christopher Bostic 2017-06-06 16:08:46 -0500 1276) }
cd0fdb5c07b27 (Christopher Bostic 2017-06-06 16:08:46 -0500 1277)
cd0fdb5c07b27 (Christopher Bostic 2017-06-06 16:08:46 -0500 1278) static DEVICE_ATTR(rescan, 0200, NULL, master_rescan_store);
cd0fdb5c07b27 (Christopher Bostic 2017-06-06 16:08:46 -0500 1279)
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 1280) static ssize_t master_break_store(struct device *dev,
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 1281) struct device_attribute *attr, const char *buf, size_t count)
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 1282) {
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 1283) struct fsi_master *master = to_fsi_master(dev);
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 1284)
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 1285) fsi_master_break(master, 0);
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 1286)
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 1287) return count;
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 1288) }
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 1289)
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 1290) static DEVICE_ATTR(break, 0200, NULL, master_break_store);
125739cbc1c3b (Jeremy Kerr 2017-06-06 16:08:49 -0500 1291)
cf700ba035dce (Jeremy Kerr 2019-11-08 15:49:36 +1030 1292) static struct attribute *master_attrs[] = {
cf700ba035dce (Jeremy Kerr 2019-11-08 15:49:36 +1030 1293) &dev_attr_break.attr,
cf700ba035dce (Jeremy Kerr 2019-11-08 15:49:36 +1030 1294) &dev_attr_rescan.attr,
cf700ba035dce (Jeremy Kerr 2019-11-08 15:49:36 +1030 1295) NULL
cf700ba035dce (Jeremy Kerr 2019-11-08 15:49:36 +1030 1296) };
cf700ba035dce (Jeremy Kerr 2019-11-08 15:49:36 +1030 1297)
cf700ba035dce (Jeremy Kerr 2019-11-08 15:49:36 +1030 1298) ATTRIBUTE_GROUPS(master);
cf700ba035dce (Jeremy Kerr 2019-11-08 15:49:36 +1030 1299)
56ec311fddacd (kbuild test robot 2019-11-08 15:49:40 +1030 1300) static struct class fsi_master_class = {
2e32c2d675ac1 (Jeremy Kerr 2019-11-08 15:49:35 +1030 1301) .name = "fsi-master",
cf700ba035dce (Jeremy Kerr 2019-11-08 15:49:36 +1030 1302) .dev_groups = master_groups,
2e32c2d675ac1 (Jeremy Kerr 2019-11-08 15:49:35 +1030 1303) };
2e32c2d675ac1 (Jeremy Kerr 2019-11-08 15:49:35 +1030 1304)
09aecfab93b8f (Jeremy Kerr 2017-06-06 16:08:36 -0500 1305) int fsi_master_register(struct fsi_master *master)
09aecfab93b8f (Jeremy Kerr 2017-06-06 16:08:36 -0500 1306) {
09aecfab93b8f (Jeremy Kerr 2017-06-06 16:08:36 -0500 1307) int rc;
f3aa2c6f98e53 (Christopher Bostic 2018-02-12 15:45:49 +1030 1308) struct device_node *np;
09aecfab93b8f (Jeremy Kerr 2017-06-06 16:08:36 -0500 1309)
9840fcd8cc43b (Benjamin Herrenschmidt 2018-06-21 18:00:05 +1000 1310) mutex_init(&master->scan_lock);
09aecfab93b8f (Jeremy Kerr 2017-06-06 16:08:36 -0500 1311) master->idx = ida_simple_get(&master_ida, 0, INT_MAX, GFP_KERNEL);
09aecfab93b8f (Jeremy Kerr 2017-06-06 16:08:36 -0500 1312) dev_set_name(&master->dev, "fsi%d", master->idx);
2e32c2d675ac1 (Jeremy Kerr 2019-11-08 15:49:35 +1030 1313) master->dev.class = &fsi_master_class;
09aecfab93b8f (Jeremy Kerr 2017-06-06 16:08:36 -0500 1314)
09aecfab93b8f (Jeremy Kerr 2017-06-06 16:08:36 -0500 1315) rc = device_register(&master->dev);
414c1026319bc (Jeremy Kerr 2017-06-06 16:08:38 -0500 1316) if (rc) {
09aecfab93b8f (Jeremy Kerr 2017-06-06 16:08:36 -0500 1317) ida_simple_remove(&master_ida, master->idx);
414c1026319bc (Jeremy Kerr 2017-06-06 16:08:38 -0500 1318) return rc;
414c1026319bc (Jeremy Kerr 2017-06-06 16:08:38 -0500 1319) }
09aecfab93b8f (Jeremy Kerr 2017-06-06 16:08:36 -0500 1320)
f3aa2c6f98e53 (Christopher Bostic 2018-02-12 15:45:49 +1030 1321) np = dev_of_node(&master->dev);
9840fcd8cc43b (Benjamin Herrenschmidt 2018-06-21 18:00:05 +1000 1322) if (!of_property_read_bool(np, "no-scan-on-init")) {
9840fcd8cc43b (Benjamin Herrenschmidt 2018-06-21 18:00:05 +1000 1323) mutex_lock(&master->scan_lock);
f3aa2c6f98e53 (Christopher Bostic 2018-02-12 15:45:49 +1030 1324) fsi_master_scan(master);
9840fcd8cc43b (Benjamin Herrenschmidt 2018-06-21 18:00:05 +1000 1325) mutex_unlock(&master->scan_lock);
9840fcd8cc43b (Benjamin Herrenschmidt 2018-06-21 18:00:05 +1000 1326) }
cd0fdb5c07b27 (Christopher Bostic 2017-06-06 16:08:46 -0500 1327)
414c1026319bc (Jeremy Kerr 2017-06-06 16:08:38 -0500 1328) return 0;
09aecfab93b8f (Jeremy Kerr 2017-06-06 16:08:36 -0500 1329) }
09aecfab93b8f (Jeremy Kerr 2017-06-06 16:08:36 -0500 1330) EXPORT_SYMBOL_GPL(fsi_master_register);
09aecfab93b8f (Jeremy Kerr 2017-06-06 16:08:36 -0500 1331)
09aecfab93b8f (Jeremy Kerr 2017-06-06 16:08:36 -0500 1332) void fsi_master_unregister(struct fsi_master *master)
09aecfab93b8f (Jeremy Kerr 2017-06-06 16:08:36 -0500 1333) {
09aecfab93b8f (Jeremy Kerr 2017-06-06 16:08:36 -0500 1334) if (master->idx >= 0) {
09aecfab93b8f (Jeremy Kerr 2017-06-06 16:08:36 -0500 1335) ida_simple_remove(&master_ida, master->idx);
09aecfab93b8f (Jeremy Kerr 2017-06-06 16:08:36 -0500 1336) master->idx = -1;
09aecfab93b8f (Jeremy Kerr 2017-06-06 16:08:36 -0500 1337) }
09aecfab93b8f (Jeremy Kerr 2017-06-06 16:08:36 -0500 1338)
9840fcd8cc43b (Benjamin Herrenschmidt 2018-06-21 18:00:05 +1000 1339) mutex_lock(&master->scan_lock);
cd0fdb5c07b27 (Christopher Bostic 2017-06-06 16:08:46 -0500 1340) fsi_master_unscan(master);
9840fcd8cc43b (Benjamin Herrenschmidt 2018-06-21 18:00:05 +1000 1341) mutex_unlock(&master->scan_lock);
09aecfab93b8f (Jeremy Kerr 2017-06-06 16:08:36 -0500 1342) device_unregister(&master->dev);
09aecfab93b8f (Jeremy Kerr 2017-06-06 16:08:36 -0500 1343) }
09aecfab93b8f (Jeremy Kerr 2017-06-06 16:08:36 -0500 1344) EXPORT_SYMBOL_GPL(fsi_master_unregister);
09aecfab93b8f (Jeremy Kerr 2017-06-06 16:08:36 -0500 1345)
0508ad1fff11a (Jeremy Kerr 2017-02-01 10:53:41 -0600 1346) /* FSI core & Linux bus type definitions */
0508ad1fff11a (Jeremy Kerr 2017-02-01 10:53:41 -0600 1347)
dd37eed7db0f7 (Jeremy Kerr 2017-02-01 10:53:43 -0600 1348) static int fsi_bus_match(struct device *dev, struct device_driver *drv)
dd37eed7db0f7 (Jeremy Kerr 2017-02-01 10:53:43 -0600 1349) {
dd37eed7db0f7 (Jeremy Kerr 2017-02-01 10:53:43 -0600 1350) struct fsi_device *fsi_dev = to_fsi_dev(dev);
dd37eed7db0f7 (Jeremy Kerr 2017-02-01 10:53:43 -0600 1351) struct fsi_driver *fsi_drv = to_fsi_drv(drv);
dd37eed7db0f7 (Jeremy Kerr 2017-02-01 10:53:43 -0600 1352) const struct fsi_device_id *id;
dd37eed7db0f7 (Jeremy Kerr 2017-02-01 10:53:43 -0600 1353)
dd37eed7db0f7 (Jeremy Kerr 2017-02-01 10:53:43 -0600 1354) if (!fsi_drv->id_table)
dd37eed7db0f7 (Jeremy Kerr 2017-02-01 10:53:43 -0600 1355) return 0;
dd37eed7db0f7 (Jeremy Kerr 2017-02-01 10:53:43 -0600 1356)
dd37eed7db0f7 (Jeremy Kerr 2017-02-01 10:53:43 -0600 1357) for (id = fsi_drv->id_table; id->engine_type; id++) {
dd37eed7db0f7 (Jeremy Kerr 2017-02-01 10:53:43 -0600 1358) if (id->engine_type != fsi_dev->engine_type)
dd37eed7db0f7 (Jeremy Kerr 2017-02-01 10:53:43 -0600 1359) continue;
dd37eed7db0f7 (Jeremy Kerr 2017-02-01 10:53:43 -0600 1360) if (id->version == FSI_VERSION_ANY ||
dd37eed7db0f7 (Jeremy Kerr 2017-02-01 10:53:43 -0600 1361) id->version == fsi_dev->version)
dd37eed7db0f7 (Jeremy Kerr 2017-02-01 10:53:43 -0600 1362) return 1;
dd37eed7db0f7 (Jeremy Kerr 2017-02-01 10:53:43 -0600 1363) }
dd37eed7db0f7 (Jeremy Kerr 2017-02-01 10:53:43 -0600 1364)
dd37eed7db0f7 (Jeremy Kerr 2017-02-01 10:53:43 -0600 1365) return 0;
dd37eed7db0f7 (Jeremy Kerr 2017-02-01 10:53:43 -0600 1366) }
dd37eed7db0f7 (Jeremy Kerr 2017-02-01 10:53:43 -0600 1367)
356d8009a5a45 (Christopher Bostic 2017-06-06 16:08:48 -0500 1368) int fsi_driver_register(struct fsi_driver *fsi_drv)
356d8009a5a45 (Christopher Bostic 2017-06-06 16:08:48 -0500 1369) {
356d8009a5a45 (Christopher Bostic 2017-06-06 16:08:48 -0500 1370) if (!fsi_drv)
356d8009a5a45 (Christopher Bostic 2017-06-06 16:08:48 -0500 1371) return -EINVAL;
356d8009a5a45 (Christopher Bostic 2017-06-06 16:08:48 -0500 1372) if (!fsi_drv->id_table)
356d8009a5a45 (Christopher Bostic 2017-06-06 16:08:48 -0500 1373) return -EINVAL;
356d8009a5a45 (Christopher Bostic 2017-06-06 16:08:48 -0500 1374)
356d8009a5a45 (Christopher Bostic 2017-06-06 16:08:48 -0500 1375) return driver_register(&fsi_drv->drv);
356d8009a5a45 (Christopher Bostic 2017-06-06 16:08:48 -0500 1376) }
356d8009a5a45 (Christopher Bostic 2017-06-06 16:08:48 -0500 1377) EXPORT_SYMBOL_GPL(fsi_driver_register);
356d8009a5a45 (Christopher Bostic 2017-06-06 16:08:48 -0500 1378)
356d8009a5a45 (Christopher Bostic 2017-06-06 16:08:48 -0500 1379) void fsi_driver_unregister(struct fsi_driver *fsi_drv)
356d8009a5a45 (Christopher Bostic 2017-06-06 16:08:48 -0500 1380) {
356d8009a5a45 (Christopher Bostic 2017-06-06 16:08:48 -0500 1381) driver_unregister(&fsi_drv->drv);
356d8009a5a45 (Christopher Bostic 2017-06-06 16:08:48 -0500 1382) }
356d8009a5a45 (Christopher Bostic 2017-06-06 16:08:48 -0500 1383) EXPORT_SYMBOL_GPL(fsi_driver_unregister);
356d8009a5a45 (Christopher Bostic 2017-06-06 16:08:48 -0500 1384)
0508ad1fff11a (Jeremy Kerr 2017-02-01 10:53:41 -0600 1385) struct bus_type fsi_bus_type = {
0508ad1fff11a (Jeremy Kerr 2017-02-01 10:53:41 -0600 1386) .name = "fsi",
dd37eed7db0f7 (Jeremy Kerr 2017-02-01 10:53:43 -0600 1387) .match = fsi_bus_match,
0508ad1fff11a (Jeremy Kerr 2017-02-01 10:53:41 -0600 1388) };
0508ad1fff11a (Jeremy Kerr 2017-02-01 10:53:41 -0600 1389) EXPORT_SYMBOL_GPL(fsi_bus_type);
0508ad1fff11a (Jeremy Kerr 2017-02-01 10:53:41 -0600 1390)
496f8931b6460 (Joel Stanley 2017-07-11 17:00:39 +0930 1391) static int __init fsi_init(void)
0508ad1fff11a (Jeremy Kerr 2017-02-01 10:53:41 -0600 1392) {
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 1393) int rc;
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 1394)
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 1395) rc = alloc_chrdev_region(&fsi_base_dev, 0, FSI_CHAR_MAX_DEVICES, "fsi");
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 1396) if (rc)
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 1397) return rc;
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 1398) rc = bus_register(&fsi_bus_type);
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 1399) if (rc)
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 1400) goto fail_bus;
2e32c2d675ac1 (Jeremy Kerr 2019-11-08 15:49:35 +1030 1401)
2e32c2d675ac1 (Jeremy Kerr 2019-11-08 15:49:35 +1030 1402) rc = class_register(&fsi_master_class);
2e32c2d675ac1 (Jeremy Kerr 2019-11-08 15:49:35 +1030 1403) if (rc)
2e32c2d675ac1 (Jeremy Kerr 2019-11-08 15:49:35 +1030 1404) goto fail_class;
2e32c2d675ac1 (Jeremy Kerr 2019-11-08 15:49:35 +1030 1405)
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 1406) return 0;
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 1407)
2e32c2d675ac1 (Jeremy Kerr 2019-11-08 15:49:35 +1030 1408) fail_class:
2e32c2d675ac1 (Jeremy Kerr 2019-11-08 15:49:35 +1030 1409) bus_unregister(&fsi_bus_type);
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 1410) fail_bus:
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 1411) unregister_chrdev_region(fsi_base_dev, FSI_CHAR_MAX_DEVICES);
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 1412) return rc;
0508ad1fff11a (Jeremy Kerr 2017-02-01 10:53:41 -0600 1413) }
496f8931b6460 (Joel Stanley 2017-07-11 17:00:39 +0930 1414) postcore_initcall(fsi_init);
0508ad1fff11a (Jeremy Kerr 2017-02-01 10:53:41 -0600 1415)
0508ad1fff11a (Jeremy Kerr 2017-02-01 10:53:41 -0600 1416) static void fsi_exit(void)
0508ad1fff11a (Jeremy Kerr 2017-02-01 10:53:41 -0600 1417) {
2e32c2d675ac1 (Jeremy Kerr 2019-11-08 15:49:35 +1030 1418) class_unregister(&fsi_master_class);
0508ad1fff11a (Jeremy Kerr 2017-02-01 10:53:41 -0600 1419) bus_unregister(&fsi_bus_type);
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 1420) unregister_chrdev_region(fsi_base_dev, FSI_CHAR_MAX_DEVICES);
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 1421) ida_destroy(&fsi_minor_ida);
0508ad1fff11a (Jeremy Kerr 2017-02-01 10:53:41 -0600 1422) }
0508ad1fff11a (Jeremy Kerr 2017-02-01 10:53:41 -0600 1423) module_exit(fsi_exit);
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 1424) module_param(discard_errors, int, 0664);
acb7e8f7448ef (Christopher Bostic 2017-06-06 16:08:59 -0500 1425) MODULE_LICENSE("GPL");
1fa847d74a75b (Jeremy Kerr 2017-06-06 16:08:52 -0500 1426) MODULE_PARM_DESC(discard_errors, "Don't invoke error handling on bus accesses");