162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2018 Cadence Design Systems Inc. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Author: Boris Brezillon <boris.brezillon@bootlin.com> 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/atomic.h> 962306a36Sopenharmony_ci#include <linux/bug.h> 1062306a36Sopenharmony_ci#include <linux/device.h> 1162306a36Sopenharmony_ci#include <linux/err.h> 1262306a36Sopenharmony_ci#include <linux/export.h> 1362306a36Sopenharmony_ci#include <linux/kernel.h> 1462306a36Sopenharmony_ci#include <linux/list.h> 1562306a36Sopenharmony_ci#include <linux/of.h> 1662306a36Sopenharmony_ci#include <linux/slab.h> 1762306a36Sopenharmony_ci#include <linux/spinlock.h> 1862306a36Sopenharmony_ci#include <linux/workqueue.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#include "internals.h" 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_cistatic DEFINE_IDR(i3c_bus_idr); 2362306a36Sopenharmony_cistatic DEFINE_MUTEX(i3c_core_lock); 2462306a36Sopenharmony_cistatic int __i3c_first_dynamic_bus_num; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci/** 2762306a36Sopenharmony_ci * i3c_bus_maintenance_lock - Lock the bus for a maintenance operation 2862306a36Sopenharmony_ci * @bus: I3C bus to take the lock on 2962306a36Sopenharmony_ci * 3062306a36Sopenharmony_ci * This function takes the bus lock so that no other operations can occur on 3162306a36Sopenharmony_ci * the bus. This is needed for all kind of bus maintenance operation, like 3262306a36Sopenharmony_ci * - enabling/disabling slave events 3362306a36Sopenharmony_ci * - re-triggering DAA 3462306a36Sopenharmony_ci * - changing the dynamic address of a device 3562306a36Sopenharmony_ci * - relinquishing mastership 3662306a36Sopenharmony_ci * - ... 3762306a36Sopenharmony_ci * 3862306a36Sopenharmony_ci * The reason for this kind of locking is that we don't want drivers and core 3962306a36Sopenharmony_ci * logic to rely on I3C device information that could be changed behind their 4062306a36Sopenharmony_ci * back. 4162306a36Sopenharmony_ci */ 4262306a36Sopenharmony_cistatic void i3c_bus_maintenance_lock(struct i3c_bus *bus) 4362306a36Sopenharmony_ci{ 4462306a36Sopenharmony_ci down_write(&bus->lock); 4562306a36Sopenharmony_ci} 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci/** 4862306a36Sopenharmony_ci * i3c_bus_maintenance_unlock - Release the bus lock after a maintenance 4962306a36Sopenharmony_ci * operation 5062306a36Sopenharmony_ci * @bus: I3C bus to release the lock on 5162306a36Sopenharmony_ci * 5262306a36Sopenharmony_ci * Should be called when the bus maintenance operation is done. See 5362306a36Sopenharmony_ci * i3c_bus_maintenance_lock() for more details on what these maintenance 5462306a36Sopenharmony_ci * operations are. 5562306a36Sopenharmony_ci */ 5662306a36Sopenharmony_cistatic void i3c_bus_maintenance_unlock(struct i3c_bus *bus) 5762306a36Sopenharmony_ci{ 5862306a36Sopenharmony_ci up_write(&bus->lock); 5962306a36Sopenharmony_ci} 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci/** 6262306a36Sopenharmony_ci * i3c_bus_normaluse_lock - Lock the bus for a normal operation 6362306a36Sopenharmony_ci * @bus: I3C bus to take the lock on 6462306a36Sopenharmony_ci * 6562306a36Sopenharmony_ci * This function takes the bus lock for any operation that is not a maintenance 6662306a36Sopenharmony_ci * operation (see i3c_bus_maintenance_lock() for a non-exhaustive list of 6762306a36Sopenharmony_ci * maintenance operations). Basically all communications with I3C devices are 6862306a36Sopenharmony_ci * normal operations (HDR, SDR transfers or CCC commands that do not change bus 6962306a36Sopenharmony_ci * state or I3C dynamic address). 7062306a36Sopenharmony_ci * 7162306a36Sopenharmony_ci * Note that this lock is not guaranteeing serialization of normal operations. 7262306a36Sopenharmony_ci * In other words, transfer requests passed to the I3C master can be submitted 7362306a36Sopenharmony_ci * in parallel and I3C master drivers have to use their own locking to make 7462306a36Sopenharmony_ci * sure two different communications are not inter-mixed, or access to the 7562306a36Sopenharmony_ci * output/input queue is not done while the engine is busy. 7662306a36Sopenharmony_ci */ 7762306a36Sopenharmony_civoid i3c_bus_normaluse_lock(struct i3c_bus *bus) 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci down_read(&bus->lock); 8062306a36Sopenharmony_ci} 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci/** 8362306a36Sopenharmony_ci * i3c_bus_normaluse_unlock - Release the bus lock after a normal operation 8462306a36Sopenharmony_ci * @bus: I3C bus to release the lock on 8562306a36Sopenharmony_ci * 8662306a36Sopenharmony_ci * Should be called when a normal operation is done. See 8762306a36Sopenharmony_ci * i3c_bus_normaluse_lock() for more details on what these normal operations 8862306a36Sopenharmony_ci * are. 8962306a36Sopenharmony_ci */ 9062306a36Sopenharmony_civoid i3c_bus_normaluse_unlock(struct i3c_bus *bus) 9162306a36Sopenharmony_ci{ 9262306a36Sopenharmony_ci up_read(&bus->lock); 9362306a36Sopenharmony_ci} 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_cistatic struct i3c_master_controller * 9662306a36Sopenharmony_cii3c_bus_to_i3c_master(struct i3c_bus *i3cbus) 9762306a36Sopenharmony_ci{ 9862306a36Sopenharmony_ci return container_of(i3cbus, struct i3c_master_controller, bus); 9962306a36Sopenharmony_ci} 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_cistatic struct i3c_master_controller *dev_to_i3cmaster(struct device *dev) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci return container_of(dev, struct i3c_master_controller, dev); 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cistatic const struct device_type i3c_device_type; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_cistatic struct i3c_bus *dev_to_i3cbus(struct device *dev) 10962306a36Sopenharmony_ci{ 11062306a36Sopenharmony_ci struct i3c_master_controller *master; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci if (dev->type == &i3c_device_type) 11362306a36Sopenharmony_ci return dev_to_i3cdev(dev)->bus; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci master = dev_to_i3cmaster(dev); 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci return &master->bus; 11862306a36Sopenharmony_ci} 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_cistatic struct i3c_dev_desc *dev_to_i3cdesc(struct device *dev) 12162306a36Sopenharmony_ci{ 12262306a36Sopenharmony_ci struct i3c_master_controller *master; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci if (dev->type == &i3c_device_type) 12562306a36Sopenharmony_ci return dev_to_i3cdev(dev)->desc; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci master = dev_to_i3cmaster(dev); 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci return master->this; 13062306a36Sopenharmony_ci} 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_cistatic ssize_t bcr_show(struct device *dev, 13362306a36Sopenharmony_ci struct device_attribute *da, 13462306a36Sopenharmony_ci char *buf) 13562306a36Sopenharmony_ci{ 13662306a36Sopenharmony_ci struct i3c_bus *bus = dev_to_i3cbus(dev); 13762306a36Sopenharmony_ci struct i3c_dev_desc *desc; 13862306a36Sopenharmony_ci ssize_t ret; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci i3c_bus_normaluse_lock(bus); 14162306a36Sopenharmony_ci desc = dev_to_i3cdesc(dev); 14262306a36Sopenharmony_ci ret = sprintf(buf, "%x\n", desc->info.bcr); 14362306a36Sopenharmony_ci i3c_bus_normaluse_unlock(bus); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci return ret; 14662306a36Sopenharmony_ci} 14762306a36Sopenharmony_cistatic DEVICE_ATTR_RO(bcr); 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_cistatic ssize_t dcr_show(struct device *dev, 15062306a36Sopenharmony_ci struct device_attribute *da, 15162306a36Sopenharmony_ci char *buf) 15262306a36Sopenharmony_ci{ 15362306a36Sopenharmony_ci struct i3c_bus *bus = dev_to_i3cbus(dev); 15462306a36Sopenharmony_ci struct i3c_dev_desc *desc; 15562306a36Sopenharmony_ci ssize_t ret; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci i3c_bus_normaluse_lock(bus); 15862306a36Sopenharmony_ci desc = dev_to_i3cdesc(dev); 15962306a36Sopenharmony_ci ret = sprintf(buf, "%x\n", desc->info.dcr); 16062306a36Sopenharmony_ci i3c_bus_normaluse_unlock(bus); 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci return ret; 16362306a36Sopenharmony_ci} 16462306a36Sopenharmony_cistatic DEVICE_ATTR_RO(dcr); 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_cistatic ssize_t pid_show(struct device *dev, 16762306a36Sopenharmony_ci struct device_attribute *da, 16862306a36Sopenharmony_ci char *buf) 16962306a36Sopenharmony_ci{ 17062306a36Sopenharmony_ci struct i3c_bus *bus = dev_to_i3cbus(dev); 17162306a36Sopenharmony_ci struct i3c_dev_desc *desc; 17262306a36Sopenharmony_ci ssize_t ret; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci i3c_bus_normaluse_lock(bus); 17562306a36Sopenharmony_ci desc = dev_to_i3cdesc(dev); 17662306a36Sopenharmony_ci ret = sprintf(buf, "%llx\n", desc->info.pid); 17762306a36Sopenharmony_ci i3c_bus_normaluse_unlock(bus); 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci return ret; 18062306a36Sopenharmony_ci} 18162306a36Sopenharmony_cistatic DEVICE_ATTR_RO(pid); 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_cistatic ssize_t dynamic_address_show(struct device *dev, 18462306a36Sopenharmony_ci struct device_attribute *da, 18562306a36Sopenharmony_ci char *buf) 18662306a36Sopenharmony_ci{ 18762306a36Sopenharmony_ci struct i3c_bus *bus = dev_to_i3cbus(dev); 18862306a36Sopenharmony_ci struct i3c_dev_desc *desc; 18962306a36Sopenharmony_ci ssize_t ret; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci i3c_bus_normaluse_lock(bus); 19262306a36Sopenharmony_ci desc = dev_to_i3cdesc(dev); 19362306a36Sopenharmony_ci ret = sprintf(buf, "%02x\n", desc->info.dyn_addr); 19462306a36Sopenharmony_ci i3c_bus_normaluse_unlock(bus); 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci return ret; 19762306a36Sopenharmony_ci} 19862306a36Sopenharmony_cistatic DEVICE_ATTR_RO(dynamic_address); 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_cistatic const char * const hdrcap_strings[] = { 20162306a36Sopenharmony_ci "hdr-ddr", "hdr-tsp", "hdr-tsl", 20262306a36Sopenharmony_ci}; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_cistatic ssize_t hdrcap_show(struct device *dev, 20562306a36Sopenharmony_ci struct device_attribute *da, 20662306a36Sopenharmony_ci char *buf) 20762306a36Sopenharmony_ci{ 20862306a36Sopenharmony_ci struct i3c_bus *bus = dev_to_i3cbus(dev); 20962306a36Sopenharmony_ci struct i3c_dev_desc *desc; 21062306a36Sopenharmony_ci ssize_t offset = 0, ret; 21162306a36Sopenharmony_ci unsigned long caps; 21262306a36Sopenharmony_ci int mode; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci i3c_bus_normaluse_lock(bus); 21562306a36Sopenharmony_ci desc = dev_to_i3cdesc(dev); 21662306a36Sopenharmony_ci caps = desc->info.hdr_cap; 21762306a36Sopenharmony_ci for_each_set_bit(mode, &caps, 8) { 21862306a36Sopenharmony_ci if (mode >= ARRAY_SIZE(hdrcap_strings)) 21962306a36Sopenharmony_ci break; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci if (!hdrcap_strings[mode]) 22262306a36Sopenharmony_ci continue; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci ret = sprintf(buf + offset, offset ? " %s" : "%s", 22562306a36Sopenharmony_ci hdrcap_strings[mode]); 22662306a36Sopenharmony_ci if (ret < 0) 22762306a36Sopenharmony_ci goto out; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci offset += ret; 23062306a36Sopenharmony_ci } 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci ret = sprintf(buf + offset, "\n"); 23362306a36Sopenharmony_ci if (ret < 0) 23462306a36Sopenharmony_ci goto out; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci ret = offset + ret; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ciout: 23962306a36Sopenharmony_ci i3c_bus_normaluse_unlock(bus); 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci return ret; 24262306a36Sopenharmony_ci} 24362306a36Sopenharmony_cistatic DEVICE_ATTR_RO(hdrcap); 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_cistatic ssize_t modalias_show(struct device *dev, 24662306a36Sopenharmony_ci struct device_attribute *da, char *buf) 24762306a36Sopenharmony_ci{ 24862306a36Sopenharmony_ci struct i3c_device *i3c = dev_to_i3cdev(dev); 24962306a36Sopenharmony_ci struct i3c_device_info devinfo; 25062306a36Sopenharmony_ci u16 manuf, part, ext; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci i3c_device_get_info(i3c, &devinfo); 25362306a36Sopenharmony_ci manuf = I3C_PID_MANUF_ID(devinfo.pid); 25462306a36Sopenharmony_ci part = I3C_PID_PART_ID(devinfo.pid); 25562306a36Sopenharmony_ci ext = I3C_PID_EXTRA_INFO(devinfo.pid); 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci if (I3C_PID_RND_LOWER_32BITS(devinfo.pid)) 25862306a36Sopenharmony_ci return sprintf(buf, "i3c:dcr%02Xmanuf%04X", devinfo.dcr, 25962306a36Sopenharmony_ci manuf); 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci return sprintf(buf, "i3c:dcr%02Xmanuf%04Xpart%04Xext%04X", 26262306a36Sopenharmony_ci devinfo.dcr, manuf, part, ext); 26362306a36Sopenharmony_ci} 26462306a36Sopenharmony_cistatic DEVICE_ATTR_RO(modalias); 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_cistatic struct attribute *i3c_device_attrs[] = { 26762306a36Sopenharmony_ci &dev_attr_bcr.attr, 26862306a36Sopenharmony_ci &dev_attr_dcr.attr, 26962306a36Sopenharmony_ci &dev_attr_pid.attr, 27062306a36Sopenharmony_ci &dev_attr_dynamic_address.attr, 27162306a36Sopenharmony_ci &dev_attr_hdrcap.attr, 27262306a36Sopenharmony_ci &dev_attr_modalias.attr, 27362306a36Sopenharmony_ci NULL, 27462306a36Sopenharmony_ci}; 27562306a36Sopenharmony_ciATTRIBUTE_GROUPS(i3c_device); 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_cistatic int i3c_device_uevent(const struct device *dev, struct kobj_uevent_env *env) 27862306a36Sopenharmony_ci{ 27962306a36Sopenharmony_ci const struct i3c_device *i3cdev = dev_to_i3cdev(dev); 28062306a36Sopenharmony_ci struct i3c_device_info devinfo; 28162306a36Sopenharmony_ci u16 manuf, part, ext; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci i3c_device_get_info(i3cdev, &devinfo); 28462306a36Sopenharmony_ci manuf = I3C_PID_MANUF_ID(devinfo.pid); 28562306a36Sopenharmony_ci part = I3C_PID_PART_ID(devinfo.pid); 28662306a36Sopenharmony_ci ext = I3C_PID_EXTRA_INFO(devinfo.pid); 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci if (I3C_PID_RND_LOWER_32BITS(devinfo.pid)) 28962306a36Sopenharmony_ci return add_uevent_var(env, "MODALIAS=i3c:dcr%02Xmanuf%04X", 29062306a36Sopenharmony_ci devinfo.dcr, manuf); 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci return add_uevent_var(env, 29362306a36Sopenharmony_ci "MODALIAS=i3c:dcr%02Xmanuf%04Xpart%04Xext%04X", 29462306a36Sopenharmony_ci devinfo.dcr, manuf, part, ext); 29562306a36Sopenharmony_ci} 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_cistatic const struct device_type i3c_device_type = { 29862306a36Sopenharmony_ci .groups = i3c_device_groups, 29962306a36Sopenharmony_ci .uevent = i3c_device_uevent, 30062306a36Sopenharmony_ci}; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_cistatic int i3c_device_match(struct device *dev, struct device_driver *drv) 30362306a36Sopenharmony_ci{ 30462306a36Sopenharmony_ci struct i3c_device *i3cdev; 30562306a36Sopenharmony_ci struct i3c_driver *i3cdrv; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci if (dev->type != &i3c_device_type) 30862306a36Sopenharmony_ci return 0; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci i3cdev = dev_to_i3cdev(dev); 31162306a36Sopenharmony_ci i3cdrv = drv_to_i3cdrv(drv); 31262306a36Sopenharmony_ci if (i3c_device_match_id(i3cdev, i3cdrv->id_table)) 31362306a36Sopenharmony_ci return 1; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci return 0; 31662306a36Sopenharmony_ci} 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_cistatic int i3c_device_probe(struct device *dev) 31962306a36Sopenharmony_ci{ 32062306a36Sopenharmony_ci struct i3c_device *i3cdev = dev_to_i3cdev(dev); 32162306a36Sopenharmony_ci struct i3c_driver *driver = drv_to_i3cdrv(dev->driver); 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci return driver->probe(i3cdev); 32462306a36Sopenharmony_ci} 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_cistatic void i3c_device_remove(struct device *dev) 32762306a36Sopenharmony_ci{ 32862306a36Sopenharmony_ci struct i3c_device *i3cdev = dev_to_i3cdev(dev); 32962306a36Sopenharmony_ci struct i3c_driver *driver = drv_to_i3cdrv(dev->driver); 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci if (driver->remove) 33262306a36Sopenharmony_ci driver->remove(i3cdev); 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci i3c_device_free_ibi(i3cdev); 33562306a36Sopenharmony_ci} 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_cistruct bus_type i3c_bus_type = { 33862306a36Sopenharmony_ci .name = "i3c", 33962306a36Sopenharmony_ci .match = i3c_device_match, 34062306a36Sopenharmony_ci .probe = i3c_device_probe, 34162306a36Sopenharmony_ci .remove = i3c_device_remove, 34262306a36Sopenharmony_ci}; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_cistatic enum i3c_addr_slot_status 34562306a36Sopenharmony_cii3c_bus_get_addr_slot_status(struct i3c_bus *bus, u16 addr) 34662306a36Sopenharmony_ci{ 34762306a36Sopenharmony_ci unsigned long status; 34862306a36Sopenharmony_ci int bitpos = addr * 2; 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci if (addr > I2C_MAX_ADDR) 35162306a36Sopenharmony_ci return I3C_ADDR_SLOT_RSVD; 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci status = bus->addrslots[bitpos / BITS_PER_LONG]; 35462306a36Sopenharmony_ci status >>= bitpos % BITS_PER_LONG; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci return status & I3C_ADDR_SLOT_STATUS_MASK; 35762306a36Sopenharmony_ci} 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_cistatic void i3c_bus_set_addr_slot_status(struct i3c_bus *bus, u16 addr, 36062306a36Sopenharmony_ci enum i3c_addr_slot_status status) 36162306a36Sopenharmony_ci{ 36262306a36Sopenharmony_ci int bitpos = addr * 2; 36362306a36Sopenharmony_ci unsigned long *ptr; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci if (addr > I2C_MAX_ADDR) 36662306a36Sopenharmony_ci return; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci ptr = bus->addrslots + (bitpos / BITS_PER_LONG); 36962306a36Sopenharmony_ci *ptr &= ~((unsigned long)I3C_ADDR_SLOT_STATUS_MASK << 37062306a36Sopenharmony_ci (bitpos % BITS_PER_LONG)); 37162306a36Sopenharmony_ci *ptr |= (unsigned long)status << (bitpos % BITS_PER_LONG); 37262306a36Sopenharmony_ci} 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_cistatic bool i3c_bus_dev_addr_is_avail(struct i3c_bus *bus, u8 addr) 37562306a36Sopenharmony_ci{ 37662306a36Sopenharmony_ci enum i3c_addr_slot_status status; 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci status = i3c_bus_get_addr_slot_status(bus, addr); 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci return status == I3C_ADDR_SLOT_FREE; 38162306a36Sopenharmony_ci} 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_cistatic int i3c_bus_get_free_addr(struct i3c_bus *bus, u8 start_addr) 38462306a36Sopenharmony_ci{ 38562306a36Sopenharmony_ci enum i3c_addr_slot_status status; 38662306a36Sopenharmony_ci u8 addr; 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci for (addr = start_addr; addr < I3C_MAX_ADDR; addr++) { 38962306a36Sopenharmony_ci status = i3c_bus_get_addr_slot_status(bus, addr); 39062306a36Sopenharmony_ci if (status == I3C_ADDR_SLOT_FREE) 39162306a36Sopenharmony_ci return addr; 39262306a36Sopenharmony_ci } 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci return -ENOMEM; 39562306a36Sopenharmony_ci} 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_cistatic void i3c_bus_init_addrslots(struct i3c_bus *bus) 39862306a36Sopenharmony_ci{ 39962306a36Sopenharmony_ci int i; 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci /* Addresses 0 to 7 are reserved. */ 40262306a36Sopenharmony_ci for (i = 0; i < 8; i++) 40362306a36Sopenharmony_ci i3c_bus_set_addr_slot_status(bus, i, I3C_ADDR_SLOT_RSVD); 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci /* 40662306a36Sopenharmony_ci * Reserve broadcast address and all addresses that might collide 40762306a36Sopenharmony_ci * with the broadcast address when facing a single bit error. 40862306a36Sopenharmony_ci */ 40962306a36Sopenharmony_ci i3c_bus_set_addr_slot_status(bus, I3C_BROADCAST_ADDR, 41062306a36Sopenharmony_ci I3C_ADDR_SLOT_RSVD); 41162306a36Sopenharmony_ci for (i = 0; i < 7; i++) 41262306a36Sopenharmony_ci i3c_bus_set_addr_slot_status(bus, I3C_BROADCAST_ADDR ^ BIT(i), 41362306a36Sopenharmony_ci I3C_ADDR_SLOT_RSVD); 41462306a36Sopenharmony_ci} 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_cistatic void i3c_bus_cleanup(struct i3c_bus *i3cbus) 41762306a36Sopenharmony_ci{ 41862306a36Sopenharmony_ci mutex_lock(&i3c_core_lock); 41962306a36Sopenharmony_ci idr_remove(&i3c_bus_idr, i3cbus->id); 42062306a36Sopenharmony_ci mutex_unlock(&i3c_core_lock); 42162306a36Sopenharmony_ci} 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_cistatic int i3c_bus_init(struct i3c_bus *i3cbus, struct device_node *np) 42462306a36Sopenharmony_ci{ 42562306a36Sopenharmony_ci int ret, start, end, id = -1; 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci init_rwsem(&i3cbus->lock); 42862306a36Sopenharmony_ci INIT_LIST_HEAD(&i3cbus->devs.i2c); 42962306a36Sopenharmony_ci INIT_LIST_HEAD(&i3cbus->devs.i3c); 43062306a36Sopenharmony_ci i3c_bus_init_addrslots(i3cbus); 43162306a36Sopenharmony_ci i3cbus->mode = I3C_BUS_MODE_PURE; 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci if (np) 43462306a36Sopenharmony_ci id = of_alias_get_id(np, "i3c"); 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci mutex_lock(&i3c_core_lock); 43762306a36Sopenharmony_ci if (id >= 0) { 43862306a36Sopenharmony_ci start = id; 43962306a36Sopenharmony_ci end = start + 1; 44062306a36Sopenharmony_ci } else { 44162306a36Sopenharmony_ci start = __i3c_first_dynamic_bus_num; 44262306a36Sopenharmony_ci end = 0; 44362306a36Sopenharmony_ci } 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci ret = idr_alloc(&i3c_bus_idr, i3cbus, start, end, GFP_KERNEL); 44662306a36Sopenharmony_ci mutex_unlock(&i3c_core_lock); 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci if (ret < 0) 44962306a36Sopenharmony_ci return ret; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci i3cbus->id = ret; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci return 0; 45462306a36Sopenharmony_ci} 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_cistatic const char * const i3c_bus_mode_strings[] = { 45762306a36Sopenharmony_ci [I3C_BUS_MODE_PURE] = "pure", 45862306a36Sopenharmony_ci [I3C_BUS_MODE_MIXED_FAST] = "mixed-fast", 45962306a36Sopenharmony_ci [I3C_BUS_MODE_MIXED_LIMITED] = "mixed-limited", 46062306a36Sopenharmony_ci [I3C_BUS_MODE_MIXED_SLOW] = "mixed-slow", 46162306a36Sopenharmony_ci}; 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_cistatic ssize_t mode_show(struct device *dev, 46462306a36Sopenharmony_ci struct device_attribute *da, 46562306a36Sopenharmony_ci char *buf) 46662306a36Sopenharmony_ci{ 46762306a36Sopenharmony_ci struct i3c_bus *i3cbus = dev_to_i3cbus(dev); 46862306a36Sopenharmony_ci ssize_t ret; 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci i3c_bus_normaluse_lock(i3cbus); 47162306a36Sopenharmony_ci if (i3cbus->mode < 0 || 47262306a36Sopenharmony_ci i3cbus->mode >= ARRAY_SIZE(i3c_bus_mode_strings) || 47362306a36Sopenharmony_ci !i3c_bus_mode_strings[i3cbus->mode]) 47462306a36Sopenharmony_ci ret = sprintf(buf, "unknown\n"); 47562306a36Sopenharmony_ci else 47662306a36Sopenharmony_ci ret = sprintf(buf, "%s\n", i3c_bus_mode_strings[i3cbus->mode]); 47762306a36Sopenharmony_ci i3c_bus_normaluse_unlock(i3cbus); 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci return ret; 48062306a36Sopenharmony_ci} 48162306a36Sopenharmony_cistatic DEVICE_ATTR_RO(mode); 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_cistatic ssize_t current_master_show(struct device *dev, 48462306a36Sopenharmony_ci struct device_attribute *da, 48562306a36Sopenharmony_ci char *buf) 48662306a36Sopenharmony_ci{ 48762306a36Sopenharmony_ci struct i3c_bus *i3cbus = dev_to_i3cbus(dev); 48862306a36Sopenharmony_ci ssize_t ret; 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci i3c_bus_normaluse_lock(i3cbus); 49162306a36Sopenharmony_ci ret = sprintf(buf, "%d-%llx\n", i3cbus->id, 49262306a36Sopenharmony_ci i3cbus->cur_master->info.pid); 49362306a36Sopenharmony_ci i3c_bus_normaluse_unlock(i3cbus); 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci return ret; 49662306a36Sopenharmony_ci} 49762306a36Sopenharmony_cistatic DEVICE_ATTR_RO(current_master); 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_cistatic ssize_t i3c_scl_frequency_show(struct device *dev, 50062306a36Sopenharmony_ci struct device_attribute *da, 50162306a36Sopenharmony_ci char *buf) 50262306a36Sopenharmony_ci{ 50362306a36Sopenharmony_ci struct i3c_bus *i3cbus = dev_to_i3cbus(dev); 50462306a36Sopenharmony_ci ssize_t ret; 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci i3c_bus_normaluse_lock(i3cbus); 50762306a36Sopenharmony_ci ret = sprintf(buf, "%ld\n", i3cbus->scl_rate.i3c); 50862306a36Sopenharmony_ci i3c_bus_normaluse_unlock(i3cbus); 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci return ret; 51162306a36Sopenharmony_ci} 51262306a36Sopenharmony_cistatic DEVICE_ATTR_RO(i3c_scl_frequency); 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_cistatic ssize_t i2c_scl_frequency_show(struct device *dev, 51562306a36Sopenharmony_ci struct device_attribute *da, 51662306a36Sopenharmony_ci char *buf) 51762306a36Sopenharmony_ci{ 51862306a36Sopenharmony_ci struct i3c_bus *i3cbus = dev_to_i3cbus(dev); 51962306a36Sopenharmony_ci ssize_t ret; 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci i3c_bus_normaluse_lock(i3cbus); 52262306a36Sopenharmony_ci ret = sprintf(buf, "%ld\n", i3cbus->scl_rate.i2c); 52362306a36Sopenharmony_ci i3c_bus_normaluse_unlock(i3cbus); 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci return ret; 52662306a36Sopenharmony_ci} 52762306a36Sopenharmony_cistatic DEVICE_ATTR_RO(i2c_scl_frequency); 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_cistatic struct attribute *i3c_masterdev_attrs[] = { 53062306a36Sopenharmony_ci &dev_attr_mode.attr, 53162306a36Sopenharmony_ci &dev_attr_current_master.attr, 53262306a36Sopenharmony_ci &dev_attr_i3c_scl_frequency.attr, 53362306a36Sopenharmony_ci &dev_attr_i2c_scl_frequency.attr, 53462306a36Sopenharmony_ci &dev_attr_bcr.attr, 53562306a36Sopenharmony_ci &dev_attr_dcr.attr, 53662306a36Sopenharmony_ci &dev_attr_pid.attr, 53762306a36Sopenharmony_ci &dev_attr_dynamic_address.attr, 53862306a36Sopenharmony_ci &dev_attr_hdrcap.attr, 53962306a36Sopenharmony_ci NULL, 54062306a36Sopenharmony_ci}; 54162306a36Sopenharmony_ciATTRIBUTE_GROUPS(i3c_masterdev); 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_cistatic void i3c_masterdev_release(struct device *dev) 54462306a36Sopenharmony_ci{ 54562306a36Sopenharmony_ci struct i3c_master_controller *master = dev_to_i3cmaster(dev); 54662306a36Sopenharmony_ci struct i3c_bus *bus = dev_to_i3cbus(dev); 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci if (master->wq) 54962306a36Sopenharmony_ci destroy_workqueue(master->wq); 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci WARN_ON(!list_empty(&bus->devs.i2c) || !list_empty(&bus->devs.i3c)); 55262306a36Sopenharmony_ci i3c_bus_cleanup(bus); 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci of_node_put(dev->of_node); 55562306a36Sopenharmony_ci} 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_cistatic const struct device_type i3c_masterdev_type = { 55862306a36Sopenharmony_ci .groups = i3c_masterdev_groups, 55962306a36Sopenharmony_ci}; 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_cistatic int i3c_bus_set_mode(struct i3c_bus *i3cbus, enum i3c_bus_mode mode, 56262306a36Sopenharmony_ci unsigned long max_i2c_scl_rate) 56362306a36Sopenharmony_ci{ 56462306a36Sopenharmony_ci struct i3c_master_controller *master = i3c_bus_to_i3c_master(i3cbus); 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci i3cbus->mode = mode; 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci switch (i3cbus->mode) { 56962306a36Sopenharmony_ci case I3C_BUS_MODE_PURE: 57062306a36Sopenharmony_ci if (!i3cbus->scl_rate.i3c) 57162306a36Sopenharmony_ci i3cbus->scl_rate.i3c = I3C_BUS_TYP_I3C_SCL_RATE; 57262306a36Sopenharmony_ci break; 57362306a36Sopenharmony_ci case I3C_BUS_MODE_MIXED_FAST: 57462306a36Sopenharmony_ci case I3C_BUS_MODE_MIXED_LIMITED: 57562306a36Sopenharmony_ci if (!i3cbus->scl_rate.i3c) 57662306a36Sopenharmony_ci i3cbus->scl_rate.i3c = I3C_BUS_TYP_I3C_SCL_RATE; 57762306a36Sopenharmony_ci if (!i3cbus->scl_rate.i2c) 57862306a36Sopenharmony_ci i3cbus->scl_rate.i2c = max_i2c_scl_rate; 57962306a36Sopenharmony_ci break; 58062306a36Sopenharmony_ci case I3C_BUS_MODE_MIXED_SLOW: 58162306a36Sopenharmony_ci if (!i3cbus->scl_rate.i2c) 58262306a36Sopenharmony_ci i3cbus->scl_rate.i2c = max_i2c_scl_rate; 58362306a36Sopenharmony_ci if (!i3cbus->scl_rate.i3c || 58462306a36Sopenharmony_ci i3cbus->scl_rate.i3c > i3cbus->scl_rate.i2c) 58562306a36Sopenharmony_ci i3cbus->scl_rate.i3c = i3cbus->scl_rate.i2c; 58662306a36Sopenharmony_ci break; 58762306a36Sopenharmony_ci default: 58862306a36Sopenharmony_ci return -EINVAL; 58962306a36Sopenharmony_ci } 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci dev_dbg(&master->dev, "i2c-scl = %ld Hz i3c-scl = %ld Hz\n", 59262306a36Sopenharmony_ci i3cbus->scl_rate.i2c, i3cbus->scl_rate.i3c); 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci /* 59562306a36Sopenharmony_ci * I3C/I2C frequency may have been overridden, check that user-provided 59662306a36Sopenharmony_ci * values are not exceeding max possible frequency. 59762306a36Sopenharmony_ci */ 59862306a36Sopenharmony_ci if (i3cbus->scl_rate.i3c > I3C_BUS_MAX_I3C_SCL_RATE || 59962306a36Sopenharmony_ci i3cbus->scl_rate.i2c > I3C_BUS_I2C_FM_PLUS_SCL_RATE) 60062306a36Sopenharmony_ci return -EINVAL; 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci return 0; 60362306a36Sopenharmony_ci} 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_cistatic struct i3c_master_controller * 60662306a36Sopenharmony_cii2c_adapter_to_i3c_master(struct i2c_adapter *adap) 60762306a36Sopenharmony_ci{ 60862306a36Sopenharmony_ci return container_of(adap, struct i3c_master_controller, i2c); 60962306a36Sopenharmony_ci} 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_cistatic struct i2c_adapter * 61262306a36Sopenharmony_cii3c_master_to_i2c_adapter(struct i3c_master_controller *master) 61362306a36Sopenharmony_ci{ 61462306a36Sopenharmony_ci return &master->i2c; 61562306a36Sopenharmony_ci} 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_cistatic void i3c_master_free_i2c_dev(struct i2c_dev_desc *dev) 61862306a36Sopenharmony_ci{ 61962306a36Sopenharmony_ci kfree(dev); 62062306a36Sopenharmony_ci} 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_cistatic struct i2c_dev_desc * 62362306a36Sopenharmony_cii3c_master_alloc_i2c_dev(struct i3c_master_controller *master, 62462306a36Sopenharmony_ci u16 addr, u8 lvr) 62562306a36Sopenharmony_ci{ 62662306a36Sopenharmony_ci struct i2c_dev_desc *dev; 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci dev = kzalloc(sizeof(*dev), GFP_KERNEL); 62962306a36Sopenharmony_ci if (!dev) 63062306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci dev->common.master = master; 63362306a36Sopenharmony_ci dev->addr = addr; 63462306a36Sopenharmony_ci dev->lvr = lvr; 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci return dev; 63762306a36Sopenharmony_ci} 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_cistatic void *i3c_ccc_cmd_dest_init(struct i3c_ccc_cmd_dest *dest, u8 addr, 64062306a36Sopenharmony_ci u16 payloadlen) 64162306a36Sopenharmony_ci{ 64262306a36Sopenharmony_ci dest->addr = addr; 64362306a36Sopenharmony_ci dest->payload.len = payloadlen; 64462306a36Sopenharmony_ci if (payloadlen) 64562306a36Sopenharmony_ci dest->payload.data = kzalloc(payloadlen, GFP_KERNEL); 64662306a36Sopenharmony_ci else 64762306a36Sopenharmony_ci dest->payload.data = NULL; 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci return dest->payload.data; 65062306a36Sopenharmony_ci} 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_cistatic void i3c_ccc_cmd_dest_cleanup(struct i3c_ccc_cmd_dest *dest) 65362306a36Sopenharmony_ci{ 65462306a36Sopenharmony_ci kfree(dest->payload.data); 65562306a36Sopenharmony_ci} 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_cistatic void i3c_ccc_cmd_init(struct i3c_ccc_cmd *cmd, bool rnw, u8 id, 65862306a36Sopenharmony_ci struct i3c_ccc_cmd_dest *dests, 65962306a36Sopenharmony_ci unsigned int ndests) 66062306a36Sopenharmony_ci{ 66162306a36Sopenharmony_ci cmd->rnw = rnw ? 1 : 0; 66262306a36Sopenharmony_ci cmd->id = id; 66362306a36Sopenharmony_ci cmd->dests = dests; 66462306a36Sopenharmony_ci cmd->ndests = ndests; 66562306a36Sopenharmony_ci cmd->err = I3C_ERROR_UNKNOWN; 66662306a36Sopenharmony_ci} 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_cistatic int i3c_master_send_ccc_cmd_locked(struct i3c_master_controller *master, 66962306a36Sopenharmony_ci struct i3c_ccc_cmd *cmd) 67062306a36Sopenharmony_ci{ 67162306a36Sopenharmony_ci int ret; 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci if (!cmd || !master) 67462306a36Sopenharmony_ci return -EINVAL; 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci if (WARN_ON(master->init_done && 67762306a36Sopenharmony_ci !rwsem_is_locked(&master->bus.lock))) 67862306a36Sopenharmony_ci return -EINVAL; 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci if (!master->ops->send_ccc_cmd) 68162306a36Sopenharmony_ci return -ENOTSUPP; 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci if ((cmd->id & I3C_CCC_DIRECT) && (!cmd->dests || !cmd->ndests)) 68462306a36Sopenharmony_ci return -EINVAL; 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci if (master->ops->supports_ccc_cmd && 68762306a36Sopenharmony_ci !master->ops->supports_ccc_cmd(master, cmd)) 68862306a36Sopenharmony_ci return -ENOTSUPP; 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci ret = master->ops->send_ccc_cmd(master, cmd); 69162306a36Sopenharmony_ci if (ret) { 69262306a36Sopenharmony_ci if (cmd->err != I3C_ERROR_UNKNOWN) 69362306a36Sopenharmony_ci return cmd->err; 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci return ret; 69662306a36Sopenharmony_ci } 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci return 0; 69962306a36Sopenharmony_ci} 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_cistatic struct i2c_dev_desc * 70262306a36Sopenharmony_cii3c_master_find_i2c_dev_by_addr(const struct i3c_master_controller *master, 70362306a36Sopenharmony_ci u16 addr) 70462306a36Sopenharmony_ci{ 70562306a36Sopenharmony_ci struct i2c_dev_desc *dev; 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci i3c_bus_for_each_i2cdev(&master->bus, dev) { 70862306a36Sopenharmony_ci if (dev->addr == addr) 70962306a36Sopenharmony_ci return dev; 71062306a36Sopenharmony_ci } 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci return NULL; 71362306a36Sopenharmony_ci} 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci/** 71662306a36Sopenharmony_ci * i3c_master_get_free_addr() - get a free address on the bus 71762306a36Sopenharmony_ci * @master: I3C master object 71862306a36Sopenharmony_ci * @start_addr: where to start searching 71962306a36Sopenharmony_ci * 72062306a36Sopenharmony_ci * This function must be called with the bus lock held in write mode. 72162306a36Sopenharmony_ci * 72262306a36Sopenharmony_ci * Return: the first free address starting at @start_addr (included) or -ENOMEM 72362306a36Sopenharmony_ci * if there's no more address available. 72462306a36Sopenharmony_ci */ 72562306a36Sopenharmony_ciint i3c_master_get_free_addr(struct i3c_master_controller *master, 72662306a36Sopenharmony_ci u8 start_addr) 72762306a36Sopenharmony_ci{ 72862306a36Sopenharmony_ci return i3c_bus_get_free_addr(&master->bus, start_addr); 72962306a36Sopenharmony_ci} 73062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(i3c_master_get_free_addr); 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_cistatic void i3c_device_release(struct device *dev) 73362306a36Sopenharmony_ci{ 73462306a36Sopenharmony_ci struct i3c_device *i3cdev = dev_to_i3cdev(dev); 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci WARN_ON(i3cdev->desc); 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci of_node_put(i3cdev->dev.of_node); 73962306a36Sopenharmony_ci kfree(i3cdev); 74062306a36Sopenharmony_ci} 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_cistatic void i3c_master_free_i3c_dev(struct i3c_dev_desc *dev) 74362306a36Sopenharmony_ci{ 74462306a36Sopenharmony_ci kfree(dev); 74562306a36Sopenharmony_ci} 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_cistatic struct i3c_dev_desc * 74862306a36Sopenharmony_cii3c_master_alloc_i3c_dev(struct i3c_master_controller *master, 74962306a36Sopenharmony_ci const struct i3c_device_info *info) 75062306a36Sopenharmony_ci{ 75162306a36Sopenharmony_ci struct i3c_dev_desc *dev; 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci dev = kzalloc(sizeof(*dev), GFP_KERNEL); 75462306a36Sopenharmony_ci if (!dev) 75562306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci dev->common.master = master; 75862306a36Sopenharmony_ci dev->info = *info; 75962306a36Sopenharmony_ci mutex_init(&dev->ibi_lock); 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci return dev; 76262306a36Sopenharmony_ci} 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_cistatic int i3c_master_rstdaa_locked(struct i3c_master_controller *master, 76562306a36Sopenharmony_ci u8 addr) 76662306a36Sopenharmony_ci{ 76762306a36Sopenharmony_ci enum i3c_addr_slot_status addrstat; 76862306a36Sopenharmony_ci struct i3c_ccc_cmd_dest dest; 76962306a36Sopenharmony_ci struct i3c_ccc_cmd cmd; 77062306a36Sopenharmony_ci int ret; 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci if (!master) 77362306a36Sopenharmony_ci return -EINVAL; 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci addrstat = i3c_bus_get_addr_slot_status(&master->bus, addr); 77662306a36Sopenharmony_ci if (addr != I3C_BROADCAST_ADDR && addrstat != I3C_ADDR_SLOT_I3C_DEV) 77762306a36Sopenharmony_ci return -EINVAL; 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci i3c_ccc_cmd_dest_init(&dest, addr, 0); 78062306a36Sopenharmony_ci i3c_ccc_cmd_init(&cmd, false, 78162306a36Sopenharmony_ci I3C_CCC_RSTDAA(addr == I3C_BROADCAST_ADDR), 78262306a36Sopenharmony_ci &dest, 1); 78362306a36Sopenharmony_ci ret = i3c_master_send_ccc_cmd_locked(master, &cmd); 78462306a36Sopenharmony_ci i3c_ccc_cmd_dest_cleanup(&dest); 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci return ret; 78762306a36Sopenharmony_ci} 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci/** 79062306a36Sopenharmony_ci * i3c_master_entdaa_locked() - start a DAA (Dynamic Address Assignment) 79162306a36Sopenharmony_ci * procedure 79262306a36Sopenharmony_ci * @master: master used to send frames on the bus 79362306a36Sopenharmony_ci * 79462306a36Sopenharmony_ci * Send a ENTDAA CCC command to start a DAA procedure. 79562306a36Sopenharmony_ci * 79662306a36Sopenharmony_ci * Note that this function only sends the ENTDAA CCC command, all the logic 79762306a36Sopenharmony_ci * behind dynamic address assignment has to be handled in the I3C master 79862306a36Sopenharmony_ci * driver. 79962306a36Sopenharmony_ci * 80062306a36Sopenharmony_ci * This function must be called with the bus lock held in write mode. 80162306a36Sopenharmony_ci * 80262306a36Sopenharmony_ci * Return: 0 in case of success, a positive I3C error code if the error is 80362306a36Sopenharmony_ci * one of the official Mx error codes, and a negative error code otherwise. 80462306a36Sopenharmony_ci */ 80562306a36Sopenharmony_ciint i3c_master_entdaa_locked(struct i3c_master_controller *master) 80662306a36Sopenharmony_ci{ 80762306a36Sopenharmony_ci struct i3c_ccc_cmd_dest dest; 80862306a36Sopenharmony_ci struct i3c_ccc_cmd cmd; 80962306a36Sopenharmony_ci int ret; 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci i3c_ccc_cmd_dest_init(&dest, I3C_BROADCAST_ADDR, 0); 81262306a36Sopenharmony_ci i3c_ccc_cmd_init(&cmd, false, I3C_CCC_ENTDAA, &dest, 1); 81362306a36Sopenharmony_ci ret = i3c_master_send_ccc_cmd_locked(master, &cmd); 81462306a36Sopenharmony_ci i3c_ccc_cmd_dest_cleanup(&dest); 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci return ret; 81762306a36Sopenharmony_ci} 81862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(i3c_master_entdaa_locked); 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_cistatic int i3c_master_enec_disec_locked(struct i3c_master_controller *master, 82162306a36Sopenharmony_ci u8 addr, bool enable, u8 evts) 82262306a36Sopenharmony_ci{ 82362306a36Sopenharmony_ci struct i3c_ccc_events *events; 82462306a36Sopenharmony_ci struct i3c_ccc_cmd_dest dest; 82562306a36Sopenharmony_ci struct i3c_ccc_cmd cmd; 82662306a36Sopenharmony_ci int ret; 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci events = i3c_ccc_cmd_dest_init(&dest, addr, sizeof(*events)); 82962306a36Sopenharmony_ci if (!events) 83062306a36Sopenharmony_ci return -ENOMEM; 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci events->events = evts; 83362306a36Sopenharmony_ci i3c_ccc_cmd_init(&cmd, false, 83462306a36Sopenharmony_ci enable ? 83562306a36Sopenharmony_ci I3C_CCC_ENEC(addr == I3C_BROADCAST_ADDR) : 83662306a36Sopenharmony_ci I3C_CCC_DISEC(addr == I3C_BROADCAST_ADDR), 83762306a36Sopenharmony_ci &dest, 1); 83862306a36Sopenharmony_ci ret = i3c_master_send_ccc_cmd_locked(master, &cmd); 83962306a36Sopenharmony_ci i3c_ccc_cmd_dest_cleanup(&dest); 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci return ret; 84262306a36Sopenharmony_ci} 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci/** 84562306a36Sopenharmony_ci * i3c_master_disec_locked() - send a DISEC CCC command 84662306a36Sopenharmony_ci * @master: master used to send frames on the bus 84762306a36Sopenharmony_ci * @addr: a valid I3C slave address or %I3C_BROADCAST_ADDR 84862306a36Sopenharmony_ci * @evts: events to disable 84962306a36Sopenharmony_ci * 85062306a36Sopenharmony_ci * Send a DISEC CCC command to disable some or all events coming from a 85162306a36Sopenharmony_ci * specific slave, or all devices if @addr is %I3C_BROADCAST_ADDR. 85262306a36Sopenharmony_ci * 85362306a36Sopenharmony_ci * This function must be called with the bus lock held in write mode. 85462306a36Sopenharmony_ci * 85562306a36Sopenharmony_ci * Return: 0 in case of success, a positive I3C error code if the error is 85662306a36Sopenharmony_ci * one of the official Mx error codes, and a negative error code otherwise. 85762306a36Sopenharmony_ci */ 85862306a36Sopenharmony_ciint i3c_master_disec_locked(struct i3c_master_controller *master, u8 addr, 85962306a36Sopenharmony_ci u8 evts) 86062306a36Sopenharmony_ci{ 86162306a36Sopenharmony_ci return i3c_master_enec_disec_locked(master, addr, false, evts); 86262306a36Sopenharmony_ci} 86362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(i3c_master_disec_locked); 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci/** 86662306a36Sopenharmony_ci * i3c_master_enec_locked() - send an ENEC CCC command 86762306a36Sopenharmony_ci * @master: master used to send frames on the bus 86862306a36Sopenharmony_ci * @addr: a valid I3C slave address or %I3C_BROADCAST_ADDR 86962306a36Sopenharmony_ci * @evts: events to disable 87062306a36Sopenharmony_ci * 87162306a36Sopenharmony_ci * Sends an ENEC CCC command to enable some or all events coming from a 87262306a36Sopenharmony_ci * specific slave, or all devices if @addr is %I3C_BROADCAST_ADDR. 87362306a36Sopenharmony_ci * 87462306a36Sopenharmony_ci * This function must be called with the bus lock held in write mode. 87562306a36Sopenharmony_ci * 87662306a36Sopenharmony_ci * Return: 0 in case of success, a positive I3C error code if the error is 87762306a36Sopenharmony_ci * one of the official Mx error codes, and a negative error code otherwise. 87862306a36Sopenharmony_ci */ 87962306a36Sopenharmony_ciint i3c_master_enec_locked(struct i3c_master_controller *master, u8 addr, 88062306a36Sopenharmony_ci u8 evts) 88162306a36Sopenharmony_ci{ 88262306a36Sopenharmony_ci return i3c_master_enec_disec_locked(master, addr, true, evts); 88362306a36Sopenharmony_ci} 88462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(i3c_master_enec_locked); 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci/** 88762306a36Sopenharmony_ci * i3c_master_defslvs_locked() - send a DEFSLVS CCC command 88862306a36Sopenharmony_ci * @master: master used to send frames on the bus 88962306a36Sopenharmony_ci * 89062306a36Sopenharmony_ci * Send a DEFSLVS CCC command containing all the devices known to the @master. 89162306a36Sopenharmony_ci * This is useful when you have secondary masters on the bus to propagate 89262306a36Sopenharmony_ci * device information. 89362306a36Sopenharmony_ci * 89462306a36Sopenharmony_ci * This should be called after all I3C devices have been discovered (in other 89562306a36Sopenharmony_ci * words, after the DAA procedure has finished) and instantiated in 89662306a36Sopenharmony_ci * &i3c_master_controller_ops->bus_init(). 89762306a36Sopenharmony_ci * It should also be called if a master ACKed an Hot-Join request and assigned 89862306a36Sopenharmony_ci * a dynamic address to the device joining the bus. 89962306a36Sopenharmony_ci * 90062306a36Sopenharmony_ci * This function must be called with the bus lock held in write mode. 90162306a36Sopenharmony_ci * 90262306a36Sopenharmony_ci * Return: 0 in case of success, a positive I3C error code if the error is 90362306a36Sopenharmony_ci * one of the official Mx error codes, and a negative error code otherwise. 90462306a36Sopenharmony_ci */ 90562306a36Sopenharmony_ciint i3c_master_defslvs_locked(struct i3c_master_controller *master) 90662306a36Sopenharmony_ci{ 90762306a36Sopenharmony_ci struct i3c_ccc_defslvs *defslvs; 90862306a36Sopenharmony_ci struct i3c_ccc_dev_desc *desc; 90962306a36Sopenharmony_ci struct i3c_ccc_cmd_dest dest; 91062306a36Sopenharmony_ci struct i3c_dev_desc *i3cdev; 91162306a36Sopenharmony_ci struct i2c_dev_desc *i2cdev; 91262306a36Sopenharmony_ci struct i3c_ccc_cmd cmd; 91362306a36Sopenharmony_ci struct i3c_bus *bus; 91462306a36Sopenharmony_ci bool send = false; 91562306a36Sopenharmony_ci int ndevs = 0, ret; 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci if (!master) 91862306a36Sopenharmony_ci return -EINVAL; 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci bus = i3c_master_get_bus(master); 92162306a36Sopenharmony_ci i3c_bus_for_each_i3cdev(bus, i3cdev) { 92262306a36Sopenharmony_ci ndevs++; 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci if (i3cdev == master->this) 92562306a36Sopenharmony_ci continue; 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci if (I3C_BCR_DEVICE_ROLE(i3cdev->info.bcr) == 92862306a36Sopenharmony_ci I3C_BCR_I3C_MASTER) 92962306a36Sopenharmony_ci send = true; 93062306a36Sopenharmony_ci } 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci /* No other master on the bus, skip DEFSLVS. */ 93362306a36Sopenharmony_ci if (!send) 93462306a36Sopenharmony_ci return 0; 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci i3c_bus_for_each_i2cdev(bus, i2cdev) 93762306a36Sopenharmony_ci ndevs++; 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci defslvs = i3c_ccc_cmd_dest_init(&dest, I3C_BROADCAST_ADDR, 94062306a36Sopenharmony_ci struct_size(defslvs, slaves, 94162306a36Sopenharmony_ci ndevs - 1)); 94262306a36Sopenharmony_ci if (!defslvs) 94362306a36Sopenharmony_ci return -ENOMEM; 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci defslvs->count = ndevs; 94662306a36Sopenharmony_ci defslvs->master.bcr = master->this->info.bcr; 94762306a36Sopenharmony_ci defslvs->master.dcr = master->this->info.dcr; 94862306a36Sopenharmony_ci defslvs->master.dyn_addr = master->this->info.dyn_addr << 1; 94962306a36Sopenharmony_ci defslvs->master.static_addr = I3C_BROADCAST_ADDR << 1; 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ci desc = defslvs->slaves; 95262306a36Sopenharmony_ci i3c_bus_for_each_i2cdev(bus, i2cdev) { 95362306a36Sopenharmony_ci desc->lvr = i2cdev->lvr; 95462306a36Sopenharmony_ci desc->static_addr = i2cdev->addr << 1; 95562306a36Sopenharmony_ci desc++; 95662306a36Sopenharmony_ci } 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci i3c_bus_for_each_i3cdev(bus, i3cdev) { 95962306a36Sopenharmony_ci /* Skip the I3C dev representing this master. */ 96062306a36Sopenharmony_ci if (i3cdev == master->this) 96162306a36Sopenharmony_ci continue; 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_ci desc->bcr = i3cdev->info.bcr; 96462306a36Sopenharmony_ci desc->dcr = i3cdev->info.dcr; 96562306a36Sopenharmony_ci desc->dyn_addr = i3cdev->info.dyn_addr << 1; 96662306a36Sopenharmony_ci desc->static_addr = i3cdev->info.static_addr << 1; 96762306a36Sopenharmony_ci desc++; 96862306a36Sopenharmony_ci } 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_ci i3c_ccc_cmd_init(&cmd, false, I3C_CCC_DEFSLVS, &dest, 1); 97162306a36Sopenharmony_ci ret = i3c_master_send_ccc_cmd_locked(master, &cmd); 97262306a36Sopenharmony_ci i3c_ccc_cmd_dest_cleanup(&dest); 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_ci return ret; 97562306a36Sopenharmony_ci} 97662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(i3c_master_defslvs_locked); 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_cistatic int i3c_master_setda_locked(struct i3c_master_controller *master, 97962306a36Sopenharmony_ci u8 oldaddr, u8 newaddr, bool setdasa) 98062306a36Sopenharmony_ci{ 98162306a36Sopenharmony_ci struct i3c_ccc_cmd_dest dest; 98262306a36Sopenharmony_ci struct i3c_ccc_setda *setda; 98362306a36Sopenharmony_ci struct i3c_ccc_cmd cmd; 98462306a36Sopenharmony_ci int ret; 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_ci if (!oldaddr || !newaddr) 98762306a36Sopenharmony_ci return -EINVAL; 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci setda = i3c_ccc_cmd_dest_init(&dest, oldaddr, sizeof(*setda)); 99062306a36Sopenharmony_ci if (!setda) 99162306a36Sopenharmony_ci return -ENOMEM; 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ci setda->addr = newaddr << 1; 99462306a36Sopenharmony_ci i3c_ccc_cmd_init(&cmd, false, 99562306a36Sopenharmony_ci setdasa ? I3C_CCC_SETDASA : I3C_CCC_SETNEWDA, 99662306a36Sopenharmony_ci &dest, 1); 99762306a36Sopenharmony_ci ret = i3c_master_send_ccc_cmd_locked(master, &cmd); 99862306a36Sopenharmony_ci i3c_ccc_cmd_dest_cleanup(&dest); 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci return ret; 100162306a36Sopenharmony_ci} 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_cistatic int i3c_master_setdasa_locked(struct i3c_master_controller *master, 100462306a36Sopenharmony_ci u8 static_addr, u8 dyn_addr) 100562306a36Sopenharmony_ci{ 100662306a36Sopenharmony_ci return i3c_master_setda_locked(master, static_addr, dyn_addr, true); 100762306a36Sopenharmony_ci} 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_cistatic int i3c_master_setnewda_locked(struct i3c_master_controller *master, 101062306a36Sopenharmony_ci u8 oldaddr, u8 newaddr) 101162306a36Sopenharmony_ci{ 101262306a36Sopenharmony_ci return i3c_master_setda_locked(master, oldaddr, newaddr, false); 101362306a36Sopenharmony_ci} 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_cistatic int i3c_master_getmrl_locked(struct i3c_master_controller *master, 101662306a36Sopenharmony_ci struct i3c_device_info *info) 101762306a36Sopenharmony_ci{ 101862306a36Sopenharmony_ci struct i3c_ccc_cmd_dest dest; 101962306a36Sopenharmony_ci struct i3c_ccc_mrl *mrl; 102062306a36Sopenharmony_ci struct i3c_ccc_cmd cmd; 102162306a36Sopenharmony_ci int ret; 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci mrl = i3c_ccc_cmd_dest_init(&dest, info->dyn_addr, sizeof(*mrl)); 102462306a36Sopenharmony_ci if (!mrl) 102562306a36Sopenharmony_ci return -ENOMEM; 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci /* 102862306a36Sopenharmony_ci * When the device does not have IBI payload GETMRL only returns 2 102962306a36Sopenharmony_ci * bytes of data. 103062306a36Sopenharmony_ci */ 103162306a36Sopenharmony_ci if (!(info->bcr & I3C_BCR_IBI_PAYLOAD)) 103262306a36Sopenharmony_ci dest.payload.len -= 1; 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ci i3c_ccc_cmd_init(&cmd, true, I3C_CCC_GETMRL, &dest, 1); 103562306a36Sopenharmony_ci ret = i3c_master_send_ccc_cmd_locked(master, &cmd); 103662306a36Sopenharmony_ci if (ret) 103762306a36Sopenharmony_ci goto out; 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci switch (dest.payload.len) { 104062306a36Sopenharmony_ci case 3: 104162306a36Sopenharmony_ci info->max_ibi_len = mrl->ibi_len; 104262306a36Sopenharmony_ci fallthrough; 104362306a36Sopenharmony_ci case 2: 104462306a36Sopenharmony_ci info->max_read_len = be16_to_cpu(mrl->read_len); 104562306a36Sopenharmony_ci break; 104662306a36Sopenharmony_ci default: 104762306a36Sopenharmony_ci ret = -EIO; 104862306a36Sopenharmony_ci goto out; 104962306a36Sopenharmony_ci } 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_ciout: 105262306a36Sopenharmony_ci i3c_ccc_cmd_dest_cleanup(&dest); 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci return ret; 105562306a36Sopenharmony_ci} 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_cistatic int i3c_master_getmwl_locked(struct i3c_master_controller *master, 105862306a36Sopenharmony_ci struct i3c_device_info *info) 105962306a36Sopenharmony_ci{ 106062306a36Sopenharmony_ci struct i3c_ccc_cmd_dest dest; 106162306a36Sopenharmony_ci struct i3c_ccc_mwl *mwl; 106262306a36Sopenharmony_ci struct i3c_ccc_cmd cmd; 106362306a36Sopenharmony_ci int ret; 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ci mwl = i3c_ccc_cmd_dest_init(&dest, info->dyn_addr, sizeof(*mwl)); 106662306a36Sopenharmony_ci if (!mwl) 106762306a36Sopenharmony_ci return -ENOMEM; 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci i3c_ccc_cmd_init(&cmd, true, I3C_CCC_GETMWL, &dest, 1); 107062306a36Sopenharmony_ci ret = i3c_master_send_ccc_cmd_locked(master, &cmd); 107162306a36Sopenharmony_ci if (ret) 107262306a36Sopenharmony_ci goto out; 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ci if (dest.payload.len != sizeof(*mwl)) { 107562306a36Sopenharmony_ci ret = -EIO; 107662306a36Sopenharmony_ci goto out; 107762306a36Sopenharmony_ci } 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_ci info->max_write_len = be16_to_cpu(mwl->len); 108062306a36Sopenharmony_ci 108162306a36Sopenharmony_ciout: 108262306a36Sopenharmony_ci i3c_ccc_cmd_dest_cleanup(&dest); 108362306a36Sopenharmony_ci 108462306a36Sopenharmony_ci return ret; 108562306a36Sopenharmony_ci} 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_cistatic int i3c_master_getmxds_locked(struct i3c_master_controller *master, 108862306a36Sopenharmony_ci struct i3c_device_info *info) 108962306a36Sopenharmony_ci{ 109062306a36Sopenharmony_ci struct i3c_ccc_getmxds *getmaxds; 109162306a36Sopenharmony_ci struct i3c_ccc_cmd_dest dest; 109262306a36Sopenharmony_ci struct i3c_ccc_cmd cmd; 109362306a36Sopenharmony_ci int ret; 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ci getmaxds = i3c_ccc_cmd_dest_init(&dest, info->dyn_addr, 109662306a36Sopenharmony_ci sizeof(*getmaxds)); 109762306a36Sopenharmony_ci if (!getmaxds) 109862306a36Sopenharmony_ci return -ENOMEM; 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ci i3c_ccc_cmd_init(&cmd, true, I3C_CCC_GETMXDS, &dest, 1); 110162306a36Sopenharmony_ci ret = i3c_master_send_ccc_cmd_locked(master, &cmd); 110262306a36Sopenharmony_ci if (ret) 110362306a36Sopenharmony_ci goto out; 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci if (dest.payload.len != 2 && dest.payload.len != 5) { 110662306a36Sopenharmony_ci ret = -EIO; 110762306a36Sopenharmony_ci goto out; 110862306a36Sopenharmony_ci } 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci info->max_read_ds = getmaxds->maxrd; 111162306a36Sopenharmony_ci info->max_write_ds = getmaxds->maxwr; 111262306a36Sopenharmony_ci if (dest.payload.len == 5) 111362306a36Sopenharmony_ci info->max_read_turnaround = getmaxds->maxrdturn[0] | 111462306a36Sopenharmony_ci ((u32)getmaxds->maxrdturn[1] << 8) | 111562306a36Sopenharmony_ci ((u32)getmaxds->maxrdturn[2] << 16); 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ciout: 111862306a36Sopenharmony_ci i3c_ccc_cmd_dest_cleanup(&dest); 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_ci return ret; 112162306a36Sopenharmony_ci} 112262306a36Sopenharmony_ci 112362306a36Sopenharmony_cistatic int i3c_master_gethdrcap_locked(struct i3c_master_controller *master, 112462306a36Sopenharmony_ci struct i3c_device_info *info) 112562306a36Sopenharmony_ci{ 112662306a36Sopenharmony_ci struct i3c_ccc_gethdrcap *gethdrcap; 112762306a36Sopenharmony_ci struct i3c_ccc_cmd_dest dest; 112862306a36Sopenharmony_ci struct i3c_ccc_cmd cmd; 112962306a36Sopenharmony_ci int ret; 113062306a36Sopenharmony_ci 113162306a36Sopenharmony_ci gethdrcap = i3c_ccc_cmd_dest_init(&dest, info->dyn_addr, 113262306a36Sopenharmony_ci sizeof(*gethdrcap)); 113362306a36Sopenharmony_ci if (!gethdrcap) 113462306a36Sopenharmony_ci return -ENOMEM; 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_ci i3c_ccc_cmd_init(&cmd, true, I3C_CCC_GETHDRCAP, &dest, 1); 113762306a36Sopenharmony_ci ret = i3c_master_send_ccc_cmd_locked(master, &cmd); 113862306a36Sopenharmony_ci if (ret) 113962306a36Sopenharmony_ci goto out; 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci if (dest.payload.len != 1) { 114262306a36Sopenharmony_ci ret = -EIO; 114362306a36Sopenharmony_ci goto out; 114462306a36Sopenharmony_ci } 114562306a36Sopenharmony_ci 114662306a36Sopenharmony_ci info->hdr_cap = gethdrcap->modes; 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_ciout: 114962306a36Sopenharmony_ci i3c_ccc_cmd_dest_cleanup(&dest); 115062306a36Sopenharmony_ci 115162306a36Sopenharmony_ci return ret; 115262306a36Sopenharmony_ci} 115362306a36Sopenharmony_ci 115462306a36Sopenharmony_cistatic int i3c_master_getpid_locked(struct i3c_master_controller *master, 115562306a36Sopenharmony_ci struct i3c_device_info *info) 115662306a36Sopenharmony_ci{ 115762306a36Sopenharmony_ci struct i3c_ccc_getpid *getpid; 115862306a36Sopenharmony_ci struct i3c_ccc_cmd_dest dest; 115962306a36Sopenharmony_ci struct i3c_ccc_cmd cmd; 116062306a36Sopenharmony_ci int ret, i; 116162306a36Sopenharmony_ci 116262306a36Sopenharmony_ci getpid = i3c_ccc_cmd_dest_init(&dest, info->dyn_addr, sizeof(*getpid)); 116362306a36Sopenharmony_ci if (!getpid) 116462306a36Sopenharmony_ci return -ENOMEM; 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_ci i3c_ccc_cmd_init(&cmd, true, I3C_CCC_GETPID, &dest, 1); 116762306a36Sopenharmony_ci ret = i3c_master_send_ccc_cmd_locked(master, &cmd); 116862306a36Sopenharmony_ci if (ret) 116962306a36Sopenharmony_ci goto out; 117062306a36Sopenharmony_ci 117162306a36Sopenharmony_ci info->pid = 0; 117262306a36Sopenharmony_ci for (i = 0; i < sizeof(getpid->pid); i++) { 117362306a36Sopenharmony_ci int sft = (sizeof(getpid->pid) - i - 1) * 8; 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ci info->pid |= (u64)getpid->pid[i] << sft; 117662306a36Sopenharmony_ci } 117762306a36Sopenharmony_ci 117862306a36Sopenharmony_ciout: 117962306a36Sopenharmony_ci i3c_ccc_cmd_dest_cleanup(&dest); 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_ci return ret; 118262306a36Sopenharmony_ci} 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_cistatic int i3c_master_getbcr_locked(struct i3c_master_controller *master, 118562306a36Sopenharmony_ci struct i3c_device_info *info) 118662306a36Sopenharmony_ci{ 118762306a36Sopenharmony_ci struct i3c_ccc_getbcr *getbcr; 118862306a36Sopenharmony_ci struct i3c_ccc_cmd_dest dest; 118962306a36Sopenharmony_ci struct i3c_ccc_cmd cmd; 119062306a36Sopenharmony_ci int ret; 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_ci getbcr = i3c_ccc_cmd_dest_init(&dest, info->dyn_addr, sizeof(*getbcr)); 119362306a36Sopenharmony_ci if (!getbcr) 119462306a36Sopenharmony_ci return -ENOMEM; 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_ci i3c_ccc_cmd_init(&cmd, true, I3C_CCC_GETBCR, &dest, 1); 119762306a36Sopenharmony_ci ret = i3c_master_send_ccc_cmd_locked(master, &cmd); 119862306a36Sopenharmony_ci if (ret) 119962306a36Sopenharmony_ci goto out; 120062306a36Sopenharmony_ci 120162306a36Sopenharmony_ci info->bcr = getbcr->bcr; 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ciout: 120462306a36Sopenharmony_ci i3c_ccc_cmd_dest_cleanup(&dest); 120562306a36Sopenharmony_ci 120662306a36Sopenharmony_ci return ret; 120762306a36Sopenharmony_ci} 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_cistatic int i3c_master_getdcr_locked(struct i3c_master_controller *master, 121062306a36Sopenharmony_ci struct i3c_device_info *info) 121162306a36Sopenharmony_ci{ 121262306a36Sopenharmony_ci struct i3c_ccc_getdcr *getdcr; 121362306a36Sopenharmony_ci struct i3c_ccc_cmd_dest dest; 121462306a36Sopenharmony_ci struct i3c_ccc_cmd cmd; 121562306a36Sopenharmony_ci int ret; 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_ci getdcr = i3c_ccc_cmd_dest_init(&dest, info->dyn_addr, sizeof(*getdcr)); 121862306a36Sopenharmony_ci if (!getdcr) 121962306a36Sopenharmony_ci return -ENOMEM; 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_ci i3c_ccc_cmd_init(&cmd, true, I3C_CCC_GETDCR, &dest, 1); 122262306a36Sopenharmony_ci ret = i3c_master_send_ccc_cmd_locked(master, &cmd); 122362306a36Sopenharmony_ci if (ret) 122462306a36Sopenharmony_ci goto out; 122562306a36Sopenharmony_ci 122662306a36Sopenharmony_ci info->dcr = getdcr->dcr; 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_ciout: 122962306a36Sopenharmony_ci i3c_ccc_cmd_dest_cleanup(&dest); 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_ci return ret; 123262306a36Sopenharmony_ci} 123362306a36Sopenharmony_ci 123462306a36Sopenharmony_cistatic int i3c_master_retrieve_dev_info(struct i3c_dev_desc *dev) 123562306a36Sopenharmony_ci{ 123662306a36Sopenharmony_ci struct i3c_master_controller *master = i3c_dev_get_master(dev); 123762306a36Sopenharmony_ci enum i3c_addr_slot_status slot_status; 123862306a36Sopenharmony_ci int ret; 123962306a36Sopenharmony_ci 124062306a36Sopenharmony_ci if (!dev->info.dyn_addr) 124162306a36Sopenharmony_ci return -EINVAL; 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_ci slot_status = i3c_bus_get_addr_slot_status(&master->bus, 124462306a36Sopenharmony_ci dev->info.dyn_addr); 124562306a36Sopenharmony_ci if (slot_status == I3C_ADDR_SLOT_RSVD || 124662306a36Sopenharmony_ci slot_status == I3C_ADDR_SLOT_I2C_DEV) 124762306a36Sopenharmony_ci return -EINVAL; 124862306a36Sopenharmony_ci 124962306a36Sopenharmony_ci ret = i3c_master_getpid_locked(master, &dev->info); 125062306a36Sopenharmony_ci if (ret) 125162306a36Sopenharmony_ci return ret; 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_ci ret = i3c_master_getbcr_locked(master, &dev->info); 125462306a36Sopenharmony_ci if (ret) 125562306a36Sopenharmony_ci return ret; 125662306a36Sopenharmony_ci 125762306a36Sopenharmony_ci ret = i3c_master_getdcr_locked(master, &dev->info); 125862306a36Sopenharmony_ci if (ret) 125962306a36Sopenharmony_ci return ret; 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_ci if (dev->info.bcr & I3C_BCR_MAX_DATA_SPEED_LIM) { 126262306a36Sopenharmony_ci ret = i3c_master_getmxds_locked(master, &dev->info); 126362306a36Sopenharmony_ci if (ret) 126462306a36Sopenharmony_ci return ret; 126562306a36Sopenharmony_ci } 126662306a36Sopenharmony_ci 126762306a36Sopenharmony_ci if (dev->info.bcr & I3C_BCR_IBI_PAYLOAD) 126862306a36Sopenharmony_ci dev->info.max_ibi_len = 1; 126962306a36Sopenharmony_ci 127062306a36Sopenharmony_ci i3c_master_getmrl_locked(master, &dev->info); 127162306a36Sopenharmony_ci i3c_master_getmwl_locked(master, &dev->info); 127262306a36Sopenharmony_ci 127362306a36Sopenharmony_ci if (dev->info.bcr & I3C_BCR_HDR_CAP) { 127462306a36Sopenharmony_ci ret = i3c_master_gethdrcap_locked(master, &dev->info); 127562306a36Sopenharmony_ci if (ret) 127662306a36Sopenharmony_ci return ret; 127762306a36Sopenharmony_ci } 127862306a36Sopenharmony_ci 127962306a36Sopenharmony_ci return 0; 128062306a36Sopenharmony_ci} 128162306a36Sopenharmony_ci 128262306a36Sopenharmony_cistatic void i3c_master_put_i3c_addrs(struct i3c_dev_desc *dev) 128362306a36Sopenharmony_ci{ 128462306a36Sopenharmony_ci struct i3c_master_controller *master = i3c_dev_get_master(dev); 128562306a36Sopenharmony_ci 128662306a36Sopenharmony_ci if (dev->info.static_addr) 128762306a36Sopenharmony_ci i3c_bus_set_addr_slot_status(&master->bus, 128862306a36Sopenharmony_ci dev->info.static_addr, 128962306a36Sopenharmony_ci I3C_ADDR_SLOT_FREE); 129062306a36Sopenharmony_ci 129162306a36Sopenharmony_ci if (dev->info.dyn_addr) 129262306a36Sopenharmony_ci i3c_bus_set_addr_slot_status(&master->bus, dev->info.dyn_addr, 129362306a36Sopenharmony_ci I3C_ADDR_SLOT_FREE); 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_ci if (dev->boardinfo && dev->boardinfo->init_dyn_addr) 129662306a36Sopenharmony_ci i3c_bus_set_addr_slot_status(&master->bus, dev->info.dyn_addr, 129762306a36Sopenharmony_ci I3C_ADDR_SLOT_FREE); 129862306a36Sopenharmony_ci} 129962306a36Sopenharmony_ci 130062306a36Sopenharmony_cistatic int i3c_master_get_i3c_addrs(struct i3c_dev_desc *dev) 130162306a36Sopenharmony_ci{ 130262306a36Sopenharmony_ci struct i3c_master_controller *master = i3c_dev_get_master(dev); 130362306a36Sopenharmony_ci enum i3c_addr_slot_status status; 130462306a36Sopenharmony_ci 130562306a36Sopenharmony_ci if (!dev->info.static_addr && !dev->info.dyn_addr) 130662306a36Sopenharmony_ci return 0; 130762306a36Sopenharmony_ci 130862306a36Sopenharmony_ci if (dev->info.static_addr) { 130962306a36Sopenharmony_ci status = i3c_bus_get_addr_slot_status(&master->bus, 131062306a36Sopenharmony_ci dev->info.static_addr); 131162306a36Sopenharmony_ci /* Since static address and assigned dynamic address can be 131262306a36Sopenharmony_ci * equal, allow this case to pass. 131362306a36Sopenharmony_ci */ 131462306a36Sopenharmony_ci if (status != I3C_ADDR_SLOT_FREE && 131562306a36Sopenharmony_ci dev->info.static_addr != dev->boardinfo->init_dyn_addr) 131662306a36Sopenharmony_ci return -EBUSY; 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_ci i3c_bus_set_addr_slot_status(&master->bus, 131962306a36Sopenharmony_ci dev->info.static_addr, 132062306a36Sopenharmony_ci I3C_ADDR_SLOT_I3C_DEV); 132162306a36Sopenharmony_ci } 132262306a36Sopenharmony_ci 132362306a36Sopenharmony_ci /* 132462306a36Sopenharmony_ci * ->init_dyn_addr should have been reserved before that, so, if we're 132562306a36Sopenharmony_ci * trying to apply a pre-reserved dynamic address, we should not try 132662306a36Sopenharmony_ci * to reserve the address slot a second time. 132762306a36Sopenharmony_ci */ 132862306a36Sopenharmony_ci if (dev->info.dyn_addr && 132962306a36Sopenharmony_ci (!dev->boardinfo || 133062306a36Sopenharmony_ci dev->boardinfo->init_dyn_addr != dev->info.dyn_addr)) { 133162306a36Sopenharmony_ci status = i3c_bus_get_addr_slot_status(&master->bus, 133262306a36Sopenharmony_ci dev->info.dyn_addr); 133362306a36Sopenharmony_ci if (status != I3C_ADDR_SLOT_FREE) 133462306a36Sopenharmony_ci goto err_release_static_addr; 133562306a36Sopenharmony_ci 133662306a36Sopenharmony_ci i3c_bus_set_addr_slot_status(&master->bus, dev->info.dyn_addr, 133762306a36Sopenharmony_ci I3C_ADDR_SLOT_I3C_DEV); 133862306a36Sopenharmony_ci } 133962306a36Sopenharmony_ci 134062306a36Sopenharmony_ci return 0; 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_cierr_release_static_addr: 134362306a36Sopenharmony_ci if (dev->info.static_addr) 134462306a36Sopenharmony_ci i3c_bus_set_addr_slot_status(&master->bus, 134562306a36Sopenharmony_ci dev->info.static_addr, 134662306a36Sopenharmony_ci I3C_ADDR_SLOT_FREE); 134762306a36Sopenharmony_ci 134862306a36Sopenharmony_ci return -EBUSY; 134962306a36Sopenharmony_ci} 135062306a36Sopenharmony_ci 135162306a36Sopenharmony_cistatic int i3c_master_attach_i3c_dev(struct i3c_master_controller *master, 135262306a36Sopenharmony_ci struct i3c_dev_desc *dev) 135362306a36Sopenharmony_ci{ 135462306a36Sopenharmony_ci int ret; 135562306a36Sopenharmony_ci 135662306a36Sopenharmony_ci /* 135762306a36Sopenharmony_ci * We don't attach devices to the controller until they are 135862306a36Sopenharmony_ci * addressable on the bus. 135962306a36Sopenharmony_ci */ 136062306a36Sopenharmony_ci if (!dev->info.static_addr && !dev->info.dyn_addr) 136162306a36Sopenharmony_ci return 0; 136262306a36Sopenharmony_ci 136362306a36Sopenharmony_ci ret = i3c_master_get_i3c_addrs(dev); 136462306a36Sopenharmony_ci if (ret) 136562306a36Sopenharmony_ci return ret; 136662306a36Sopenharmony_ci 136762306a36Sopenharmony_ci /* Do not attach the master device itself. */ 136862306a36Sopenharmony_ci if (master->this != dev && master->ops->attach_i3c_dev) { 136962306a36Sopenharmony_ci ret = master->ops->attach_i3c_dev(dev); 137062306a36Sopenharmony_ci if (ret) { 137162306a36Sopenharmony_ci i3c_master_put_i3c_addrs(dev); 137262306a36Sopenharmony_ci return ret; 137362306a36Sopenharmony_ci } 137462306a36Sopenharmony_ci } 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_ci list_add_tail(&dev->common.node, &master->bus.devs.i3c); 137762306a36Sopenharmony_ci 137862306a36Sopenharmony_ci return 0; 137962306a36Sopenharmony_ci} 138062306a36Sopenharmony_ci 138162306a36Sopenharmony_cistatic int i3c_master_reattach_i3c_dev(struct i3c_dev_desc *dev, 138262306a36Sopenharmony_ci u8 old_dyn_addr) 138362306a36Sopenharmony_ci{ 138462306a36Sopenharmony_ci struct i3c_master_controller *master = i3c_dev_get_master(dev); 138562306a36Sopenharmony_ci enum i3c_addr_slot_status status; 138662306a36Sopenharmony_ci int ret; 138762306a36Sopenharmony_ci 138862306a36Sopenharmony_ci if (dev->info.dyn_addr != old_dyn_addr && 138962306a36Sopenharmony_ci (!dev->boardinfo || 139062306a36Sopenharmony_ci dev->info.dyn_addr != dev->boardinfo->init_dyn_addr)) { 139162306a36Sopenharmony_ci status = i3c_bus_get_addr_slot_status(&master->bus, 139262306a36Sopenharmony_ci dev->info.dyn_addr); 139362306a36Sopenharmony_ci if (status != I3C_ADDR_SLOT_FREE) 139462306a36Sopenharmony_ci return -EBUSY; 139562306a36Sopenharmony_ci i3c_bus_set_addr_slot_status(&master->bus, 139662306a36Sopenharmony_ci dev->info.dyn_addr, 139762306a36Sopenharmony_ci I3C_ADDR_SLOT_I3C_DEV); 139862306a36Sopenharmony_ci if (old_dyn_addr) 139962306a36Sopenharmony_ci i3c_bus_set_addr_slot_status(&master->bus, old_dyn_addr, 140062306a36Sopenharmony_ci I3C_ADDR_SLOT_FREE); 140162306a36Sopenharmony_ci } 140262306a36Sopenharmony_ci 140362306a36Sopenharmony_ci if (master->ops->reattach_i3c_dev) { 140462306a36Sopenharmony_ci ret = master->ops->reattach_i3c_dev(dev, old_dyn_addr); 140562306a36Sopenharmony_ci if (ret) { 140662306a36Sopenharmony_ci i3c_master_put_i3c_addrs(dev); 140762306a36Sopenharmony_ci return ret; 140862306a36Sopenharmony_ci } 140962306a36Sopenharmony_ci } 141062306a36Sopenharmony_ci 141162306a36Sopenharmony_ci return 0; 141262306a36Sopenharmony_ci} 141362306a36Sopenharmony_ci 141462306a36Sopenharmony_cistatic void i3c_master_detach_i3c_dev(struct i3c_dev_desc *dev) 141562306a36Sopenharmony_ci{ 141662306a36Sopenharmony_ci struct i3c_master_controller *master = i3c_dev_get_master(dev); 141762306a36Sopenharmony_ci 141862306a36Sopenharmony_ci /* Do not detach the master device itself. */ 141962306a36Sopenharmony_ci if (master->this != dev && master->ops->detach_i3c_dev) 142062306a36Sopenharmony_ci master->ops->detach_i3c_dev(dev); 142162306a36Sopenharmony_ci 142262306a36Sopenharmony_ci i3c_master_put_i3c_addrs(dev); 142362306a36Sopenharmony_ci list_del(&dev->common.node); 142462306a36Sopenharmony_ci} 142562306a36Sopenharmony_ci 142662306a36Sopenharmony_cistatic int i3c_master_attach_i2c_dev(struct i3c_master_controller *master, 142762306a36Sopenharmony_ci struct i2c_dev_desc *dev) 142862306a36Sopenharmony_ci{ 142962306a36Sopenharmony_ci int ret; 143062306a36Sopenharmony_ci 143162306a36Sopenharmony_ci if (master->ops->attach_i2c_dev) { 143262306a36Sopenharmony_ci ret = master->ops->attach_i2c_dev(dev); 143362306a36Sopenharmony_ci if (ret) 143462306a36Sopenharmony_ci return ret; 143562306a36Sopenharmony_ci } 143662306a36Sopenharmony_ci 143762306a36Sopenharmony_ci list_add_tail(&dev->common.node, &master->bus.devs.i2c); 143862306a36Sopenharmony_ci 143962306a36Sopenharmony_ci return 0; 144062306a36Sopenharmony_ci} 144162306a36Sopenharmony_ci 144262306a36Sopenharmony_cistatic void i3c_master_detach_i2c_dev(struct i2c_dev_desc *dev) 144362306a36Sopenharmony_ci{ 144462306a36Sopenharmony_ci struct i3c_master_controller *master = i2c_dev_get_master(dev); 144562306a36Sopenharmony_ci 144662306a36Sopenharmony_ci list_del(&dev->common.node); 144762306a36Sopenharmony_ci 144862306a36Sopenharmony_ci if (master->ops->detach_i2c_dev) 144962306a36Sopenharmony_ci master->ops->detach_i2c_dev(dev); 145062306a36Sopenharmony_ci} 145162306a36Sopenharmony_ci 145262306a36Sopenharmony_cistatic int i3c_master_early_i3c_dev_add(struct i3c_master_controller *master, 145362306a36Sopenharmony_ci struct i3c_dev_boardinfo *boardinfo) 145462306a36Sopenharmony_ci{ 145562306a36Sopenharmony_ci struct i3c_device_info info = { 145662306a36Sopenharmony_ci .static_addr = boardinfo->static_addr, 145762306a36Sopenharmony_ci .pid = boardinfo->pid, 145862306a36Sopenharmony_ci }; 145962306a36Sopenharmony_ci struct i3c_dev_desc *i3cdev; 146062306a36Sopenharmony_ci int ret; 146162306a36Sopenharmony_ci 146262306a36Sopenharmony_ci i3cdev = i3c_master_alloc_i3c_dev(master, &info); 146362306a36Sopenharmony_ci if (IS_ERR(i3cdev)) 146462306a36Sopenharmony_ci return -ENOMEM; 146562306a36Sopenharmony_ci 146662306a36Sopenharmony_ci i3cdev->boardinfo = boardinfo; 146762306a36Sopenharmony_ci 146862306a36Sopenharmony_ci ret = i3c_master_attach_i3c_dev(master, i3cdev); 146962306a36Sopenharmony_ci if (ret) 147062306a36Sopenharmony_ci goto err_free_dev; 147162306a36Sopenharmony_ci 147262306a36Sopenharmony_ci ret = i3c_master_setdasa_locked(master, i3cdev->info.static_addr, 147362306a36Sopenharmony_ci i3cdev->boardinfo->init_dyn_addr); 147462306a36Sopenharmony_ci if (ret) 147562306a36Sopenharmony_ci goto err_detach_dev; 147662306a36Sopenharmony_ci 147762306a36Sopenharmony_ci i3cdev->info.dyn_addr = i3cdev->boardinfo->init_dyn_addr; 147862306a36Sopenharmony_ci ret = i3c_master_reattach_i3c_dev(i3cdev, 0); 147962306a36Sopenharmony_ci if (ret) 148062306a36Sopenharmony_ci goto err_rstdaa; 148162306a36Sopenharmony_ci 148262306a36Sopenharmony_ci ret = i3c_master_retrieve_dev_info(i3cdev); 148362306a36Sopenharmony_ci if (ret) 148462306a36Sopenharmony_ci goto err_rstdaa; 148562306a36Sopenharmony_ci 148662306a36Sopenharmony_ci return 0; 148762306a36Sopenharmony_ci 148862306a36Sopenharmony_cierr_rstdaa: 148962306a36Sopenharmony_ci i3c_master_rstdaa_locked(master, i3cdev->boardinfo->init_dyn_addr); 149062306a36Sopenharmony_cierr_detach_dev: 149162306a36Sopenharmony_ci i3c_master_detach_i3c_dev(i3cdev); 149262306a36Sopenharmony_cierr_free_dev: 149362306a36Sopenharmony_ci i3c_master_free_i3c_dev(i3cdev); 149462306a36Sopenharmony_ci 149562306a36Sopenharmony_ci return ret; 149662306a36Sopenharmony_ci} 149762306a36Sopenharmony_ci 149862306a36Sopenharmony_cistatic void 149962306a36Sopenharmony_cii3c_master_register_new_i3c_devs(struct i3c_master_controller *master) 150062306a36Sopenharmony_ci{ 150162306a36Sopenharmony_ci struct i3c_dev_desc *desc; 150262306a36Sopenharmony_ci int ret; 150362306a36Sopenharmony_ci 150462306a36Sopenharmony_ci if (!master->init_done) 150562306a36Sopenharmony_ci return; 150662306a36Sopenharmony_ci 150762306a36Sopenharmony_ci i3c_bus_for_each_i3cdev(&master->bus, desc) { 150862306a36Sopenharmony_ci if (desc->dev || !desc->info.dyn_addr || desc == master->this) 150962306a36Sopenharmony_ci continue; 151062306a36Sopenharmony_ci 151162306a36Sopenharmony_ci desc->dev = kzalloc(sizeof(*desc->dev), GFP_KERNEL); 151262306a36Sopenharmony_ci if (!desc->dev) 151362306a36Sopenharmony_ci continue; 151462306a36Sopenharmony_ci 151562306a36Sopenharmony_ci desc->dev->bus = &master->bus; 151662306a36Sopenharmony_ci desc->dev->desc = desc; 151762306a36Sopenharmony_ci desc->dev->dev.parent = &master->dev; 151862306a36Sopenharmony_ci desc->dev->dev.type = &i3c_device_type; 151962306a36Sopenharmony_ci desc->dev->dev.bus = &i3c_bus_type; 152062306a36Sopenharmony_ci desc->dev->dev.release = i3c_device_release; 152162306a36Sopenharmony_ci dev_set_name(&desc->dev->dev, "%d-%llx", master->bus.id, 152262306a36Sopenharmony_ci desc->info.pid); 152362306a36Sopenharmony_ci 152462306a36Sopenharmony_ci if (desc->boardinfo) 152562306a36Sopenharmony_ci desc->dev->dev.of_node = desc->boardinfo->of_node; 152662306a36Sopenharmony_ci 152762306a36Sopenharmony_ci ret = device_register(&desc->dev->dev); 152862306a36Sopenharmony_ci if (ret) { 152962306a36Sopenharmony_ci dev_err(&master->dev, 153062306a36Sopenharmony_ci "Failed to add I3C device (err = %d)\n", ret); 153162306a36Sopenharmony_ci put_device(&desc->dev->dev); 153262306a36Sopenharmony_ci } 153362306a36Sopenharmony_ci } 153462306a36Sopenharmony_ci} 153562306a36Sopenharmony_ci 153662306a36Sopenharmony_ci/** 153762306a36Sopenharmony_ci * i3c_master_do_daa() - do a DAA (Dynamic Address Assignment) 153862306a36Sopenharmony_ci * @master: master doing the DAA 153962306a36Sopenharmony_ci * 154062306a36Sopenharmony_ci * This function is instantiating an I3C device object and adding it to the 154162306a36Sopenharmony_ci * I3C device list. All device information are automatically retrieved using 154262306a36Sopenharmony_ci * standard CCC commands. 154362306a36Sopenharmony_ci * 154462306a36Sopenharmony_ci * The I3C device object is returned in case the master wants to attach 154562306a36Sopenharmony_ci * private data to it using i3c_dev_set_master_data(). 154662306a36Sopenharmony_ci * 154762306a36Sopenharmony_ci * This function must be called with the bus lock held in write mode. 154862306a36Sopenharmony_ci * 154962306a36Sopenharmony_ci * Return: a 0 in case of success, an negative error code otherwise. 155062306a36Sopenharmony_ci */ 155162306a36Sopenharmony_ciint i3c_master_do_daa(struct i3c_master_controller *master) 155262306a36Sopenharmony_ci{ 155362306a36Sopenharmony_ci int ret; 155462306a36Sopenharmony_ci 155562306a36Sopenharmony_ci i3c_bus_maintenance_lock(&master->bus); 155662306a36Sopenharmony_ci ret = master->ops->do_daa(master); 155762306a36Sopenharmony_ci i3c_bus_maintenance_unlock(&master->bus); 155862306a36Sopenharmony_ci 155962306a36Sopenharmony_ci if (ret) 156062306a36Sopenharmony_ci return ret; 156162306a36Sopenharmony_ci 156262306a36Sopenharmony_ci i3c_bus_normaluse_lock(&master->bus); 156362306a36Sopenharmony_ci i3c_master_register_new_i3c_devs(master); 156462306a36Sopenharmony_ci i3c_bus_normaluse_unlock(&master->bus); 156562306a36Sopenharmony_ci 156662306a36Sopenharmony_ci return 0; 156762306a36Sopenharmony_ci} 156862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(i3c_master_do_daa); 156962306a36Sopenharmony_ci 157062306a36Sopenharmony_ci/** 157162306a36Sopenharmony_ci * i3c_master_set_info() - set master device information 157262306a36Sopenharmony_ci * @master: master used to send frames on the bus 157362306a36Sopenharmony_ci * @info: I3C device information 157462306a36Sopenharmony_ci * 157562306a36Sopenharmony_ci * Set master device info. This should be called from 157662306a36Sopenharmony_ci * &i3c_master_controller_ops->bus_init(). 157762306a36Sopenharmony_ci * 157862306a36Sopenharmony_ci * Not all &i3c_device_info fields are meaningful for a master device. 157962306a36Sopenharmony_ci * Here is a list of fields that should be properly filled: 158062306a36Sopenharmony_ci * 158162306a36Sopenharmony_ci * - &i3c_device_info->dyn_addr 158262306a36Sopenharmony_ci * - &i3c_device_info->bcr 158362306a36Sopenharmony_ci * - &i3c_device_info->dcr 158462306a36Sopenharmony_ci * - &i3c_device_info->pid 158562306a36Sopenharmony_ci * - &i3c_device_info->hdr_cap if %I3C_BCR_HDR_CAP bit is set in 158662306a36Sopenharmony_ci * &i3c_device_info->bcr 158762306a36Sopenharmony_ci * 158862306a36Sopenharmony_ci * This function must be called with the bus lock held in maintenance mode. 158962306a36Sopenharmony_ci * 159062306a36Sopenharmony_ci * Return: 0 if @info contains valid information (not every piece of 159162306a36Sopenharmony_ci * information can be checked, but we can at least make sure @info->dyn_addr 159262306a36Sopenharmony_ci * and @info->bcr are correct), -EINVAL otherwise. 159362306a36Sopenharmony_ci */ 159462306a36Sopenharmony_ciint i3c_master_set_info(struct i3c_master_controller *master, 159562306a36Sopenharmony_ci const struct i3c_device_info *info) 159662306a36Sopenharmony_ci{ 159762306a36Sopenharmony_ci struct i3c_dev_desc *i3cdev; 159862306a36Sopenharmony_ci int ret; 159962306a36Sopenharmony_ci 160062306a36Sopenharmony_ci if (!i3c_bus_dev_addr_is_avail(&master->bus, info->dyn_addr)) 160162306a36Sopenharmony_ci return -EINVAL; 160262306a36Sopenharmony_ci 160362306a36Sopenharmony_ci if (I3C_BCR_DEVICE_ROLE(info->bcr) == I3C_BCR_I3C_MASTER && 160462306a36Sopenharmony_ci master->secondary) 160562306a36Sopenharmony_ci return -EINVAL; 160662306a36Sopenharmony_ci 160762306a36Sopenharmony_ci if (master->this) 160862306a36Sopenharmony_ci return -EINVAL; 160962306a36Sopenharmony_ci 161062306a36Sopenharmony_ci i3cdev = i3c_master_alloc_i3c_dev(master, info); 161162306a36Sopenharmony_ci if (IS_ERR(i3cdev)) 161262306a36Sopenharmony_ci return PTR_ERR(i3cdev); 161362306a36Sopenharmony_ci 161462306a36Sopenharmony_ci master->this = i3cdev; 161562306a36Sopenharmony_ci master->bus.cur_master = master->this; 161662306a36Sopenharmony_ci 161762306a36Sopenharmony_ci ret = i3c_master_attach_i3c_dev(master, i3cdev); 161862306a36Sopenharmony_ci if (ret) 161962306a36Sopenharmony_ci goto err_free_dev; 162062306a36Sopenharmony_ci 162162306a36Sopenharmony_ci return 0; 162262306a36Sopenharmony_ci 162362306a36Sopenharmony_cierr_free_dev: 162462306a36Sopenharmony_ci i3c_master_free_i3c_dev(i3cdev); 162562306a36Sopenharmony_ci 162662306a36Sopenharmony_ci return ret; 162762306a36Sopenharmony_ci} 162862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(i3c_master_set_info); 162962306a36Sopenharmony_ci 163062306a36Sopenharmony_cistatic void i3c_master_detach_free_devs(struct i3c_master_controller *master) 163162306a36Sopenharmony_ci{ 163262306a36Sopenharmony_ci struct i3c_dev_desc *i3cdev, *i3ctmp; 163362306a36Sopenharmony_ci struct i2c_dev_desc *i2cdev, *i2ctmp; 163462306a36Sopenharmony_ci 163562306a36Sopenharmony_ci list_for_each_entry_safe(i3cdev, i3ctmp, &master->bus.devs.i3c, 163662306a36Sopenharmony_ci common.node) { 163762306a36Sopenharmony_ci i3c_master_detach_i3c_dev(i3cdev); 163862306a36Sopenharmony_ci 163962306a36Sopenharmony_ci if (i3cdev->boardinfo && i3cdev->boardinfo->init_dyn_addr) 164062306a36Sopenharmony_ci i3c_bus_set_addr_slot_status(&master->bus, 164162306a36Sopenharmony_ci i3cdev->boardinfo->init_dyn_addr, 164262306a36Sopenharmony_ci I3C_ADDR_SLOT_FREE); 164362306a36Sopenharmony_ci 164462306a36Sopenharmony_ci i3c_master_free_i3c_dev(i3cdev); 164562306a36Sopenharmony_ci } 164662306a36Sopenharmony_ci 164762306a36Sopenharmony_ci list_for_each_entry_safe(i2cdev, i2ctmp, &master->bus.devs.i2c, 164862306a36Sopenharmony_ci common.node) { 164962306a36Sopenharmony_ci i3c_master_detach_i2c_dev(i2cdev); 165062306a36Sopenharmony_ci i3c_bus_set_addr_slot_status(&master->bus, 165162306a36Sopenharmony_ci i2cdev->addr, 165262306a36Sopenharmony_ci I3C_ADDR_SLOT_FREE); 165362306a36Sopenharmony_ci i3c_master_free_i2c_dev(i2cdev); 165462306a36Sopenharmony_ci } 165562306a36Sopenharmony_ci} 165662306a36Sopenharmony_ci 165762306a36Sopenharmony_ci/** 165862306a36Sopenharmony_ci * i3c_master_bus_init() - initialize an I3C bus 165962306a36Sopenharmony_ci * @master: main master initializing the bus 166062306a36Sopenharmony_ci * 166162306a36Sopenharmony_ci * This function is following all initialisation steps described in the I3C 166262306a36Sopenharmony_ci * specification: 166362306a36Sopenharmony_ci * 166462306a36Sopenharmony_ci * 1. Attach I2C devs to the master so that the master can fill its internal 166562306a36Sopenharmony_ci * device table appropriately 166662306a36Sopenharmony_ci * 166762306a36Sopenharmony_ci * 2. Call &i3c_master_controller_ops->bus_init() method to initialize 166862306a36Sopenharmony_ci * the master controller. That's usually where the bus mode is selected 166962306a36Sopenharmony_ci * (pure bus or mixed fast/slow bus) 167062306a36Sopenharmony_ci * 167162306a36Sopenharmony_ci * 3. Instruct all devices on the bus to drop their dynamic address. This is 167262306a36Sopenharmony_ci * particularly important when the bus was previously configured by someone 167362306a36Sopenharmony_ci * else (for example the bootloader) 167462306a36Sopenharmony_ci * 167562306a36Sopenharmony_ci * 4. Disable all slave events. 167662306a36Sopenharmony_ci * 167762306a36Sopenharmony_ci * 5. Reserve address slots for I3C devices with init_dyn_addr. And if devices 167862306a36Sopenharmony_ci * also have static_addr, try to pre-assign dynamic addresses requested by 167962306a36Sopenharmony_ci * the FW with SETDASA and attach corresponding statically defined I3C 168062306a36Sopenharmony_ci * devices to the master. 168162306a36Sopenharmony_ci * 168262306a36Sopenharmony_ci * 6. Do a DAA (Dynamic Address Assignment) to assign dynamic addresses to all 168362306a36Sopenharmony_ci * remaining I3C devices 168462306a36Sopenharmony_ci * 168562306a36Sopenharmony_ci * Once this is done, all I3C and I2C devices should be usable. 168662306a36Sopenharmony_ci * 168762306a36Sopenharmony_ci * Return: a 0 in case of success, an negative error code otherwise. 168862306a36Sopenharmony_ci */ 168962306a36Sopenharmony_cistatic int i3c_master_bus_init(struct i3c_master_controller *master) 169062306a36Sopenharmony_ci{ 169162306a36Sopenharmony_ci enum i3c_addr_slot_status status; 169262306a36Sopenharmony_ci struct i2c_dev_boardinfo *i2cboardinfo; 169362306a36Sopenharmony_ci struct i3c_dev_boardinfo *i3cboardinfo; 169462306a36Sopenharmony_ci struct i2c_dev_desc *i2cdev; 169562306a36Sopenharmony_ci int ret; 169662306a36Sopenharmony_ci 169762306a36Sopenharmony_ci /* 169862306a36Sopenharmony_ci * First attach all devices with static definitions provided by the 169962306a36Sopenharmony_ci * FW. 170062306a36Sopenharmony_ci */ 170162306a36Sopenharmony_ci list_for_each_entry(i2cboardinfo, &master->boardinfo.i2c, node) { 170262306a36Sopenharmony_ci status = i3c_bus_get_addr_slot_status(&master->bus, 170362306a36Sopenharmony_ci i2cboardinfo->base.addr); 170462306a36Sopenharmony_ci if (status != I3C_ADDR_SLOT_FREE) { 170562306a36Sopenharmony_ci ret = -EBUSY; 170662306a36Sopenharmony_ci goto err_detach_devs; 170762306a36Sopenharmony_ci } 170862306a36Sopenharmony_ci 170962306a36Sopenharmony_ci i3c_bus_set_addr_slot_status(&master->bus, 171062306a36Sopenharmony_ci i2cboardinfo->base.addr, 171162306a36Sopenharmony_ci I3C_ADDR_SLOT_I2C_DEV); 171262306a36Sopenharmony_ci 171362306a36Sopenharmony_ci i2cdev = i3c_master_alloc_i2c_dev(master, 171462306a36Sopenharmony_ci i2cboardinfo->base.addr, 171562306a36Sopenharmony_ci i2cboardinfo->lvr); 171662306a36Sopenharmony_ci if (IS_ERR(i2cdev)) { 171762306a36Sopenharmony_ci ret = PTR_ERR(i2cdev); 171862306a36Sopenharmony_ci goto err_detach_devs; 171962306a36Sopenharmony_ci } 172062306a36Sopenharmony_ci 172162306a36Sopenharmony_ci ret = i3c_master_attach_i2c_dev(master, i2cdev); 172262306a36Sopenharmony_ci if (ret) { 172362306a36Sopenharmony_ci i3c_master_free_i2c_dev(i2cdev); 172462306a36Sopenharmony_ci goto err_detach_devs; 172562306a36Sopenharmony_ci } 172662306a36Sopenharmony_ci } 172762306a36Sopenharmony_ci 172862306a36Sopenharmony_ci /* 172962306a36Sopenharmony_ci * Now execute the controller specific ->bus_init() routine, which 173062306a36Sopenharmony_ci * might configure its internal logic to match the bus limitations. 173162306a36Sopenharmony_ci */ 173262306a36Sopenharmony_ci ret = master->ops->bus_init(master); 173362306a36Sopenharmony_ci if (ret) 173462306a36Sopenharmony_ci goto err_detach_devs; 173562306a36Sopenharmony_ci 173662306a36Sopenharmony_ci /* 173762306a36Sopenharmony_ci * The master device should have been instantiated in ->bus_init(), 173862306a36Sopenharmony_ci * complain if this was not the case. 173962306a36Sopenharmony_ci */ 174062306a36Sopenharmony_ci if (!master->this) { 174162306a36Sopenharmony_ci dev_err(&master->dev, 174262306a36Sopenharmony_ci "master_set_info() was not called in ->bus_init()\n"); 174362306a36Sopenharmony_ci ret = -EINVAL; 174462306a36Sopenharmony_ci goto err_bus_cleanup; 174562306a36Sopenharmony_ci } 174662306a36Sopenharmony_ci 174762306a36Sopenharmony_ci /* 174862306a36Sopenharmony_ci * Reset all dynamic address that may have been assigned before 174962306a36Sopenharmony_ci * (assigned by the bootloader for example). 175062306a36Sopenharmony_ci */ 175162306a36Sopenharmony_ci ret = i3c_master_rstdaa_locked(master, I3C_BROADCAST_ADDR); 175262306a36Sopenharmony_ci if (ret && ret != I3C_ERROR_M2) 175362306a36Sopenharmony_ci goto err_bus_cleanup; 175462306a36Sopenharmony_ci 175562306a36Sopenharmony_ci /* Disable all slave events before starting DAA. */ 175662306a36Sopenharmony_ci ret = i3c_master_disec_locked(master, I3C_BROADCAST_ADDR, 175762306a36Sopenharmony_ci I3C_CCC_EVENT_SIR | I3C_CCC_EVENT_MR | 175862306a36Sopenharmony_ci I3C_CCC_EVENT_HJ); 175962306a36Sopenharmony_ci if (ret && ret != I3C_ERROR_M2) 176062306a36Sopenharmony_ci goto err_bus_cleanup; 176162306a36Sopenharmony_ci 176262306a36Sopenharmony_ci /* 176362306a36Sopenharmony_ci * Reserve init_dyn_addr first, and then try to pre-assign dynamic 176462306a36Sopenharmony_ci * address and retrieve device information if needed. 176562306a36Sopenharmony_ci * In case pre-assign dynamic address fails, setting dynamic address to 176662306a36Sopenharmony_ci * the requested init_dyn_addr is retried after DAA is done in 176762306a36Sopenharmony_ci * i3c_master_add_i3c_dev_locked(). 176862306a36Sopenharmony_ci */ 176962306a36Sopenharmony_ci list_for_each_entry(i3cboardinfo, &master->boardinfo.i3c, node) { 177062306a36Sopenharmony_ci 177162306a36Sopenharmony_ci /* 177262306a36Sopenharmony_ci * We don't reserve a dynamic address for devices that 177362306a36Sopenharmony_ci * don't explicitly request one. 177462306a36Sopenharmony_ci */ 177562306a36Sopenharmony_ci if (!i3cboardinfo->init_dyn_addr) 177662306a36Sopenharmony_ci continue; 177762306a36Sopenharmony_ci 177862306a36Sopenharmony_ci ret = i3c_bus_get_addr_slot_status(&master->bus, 177962306a36Sopenharmony_ci i3cboardinfo->init_dyn_addr); 178062306a36Sopenharmony_ci if (ret != I3C_ADDR_SLOT_FREE) { 178162306a36Sopenharmony_ci ret = -EBUSY; 178262306a36Sopenharmony_ci goto err_rstdaa; 178362306a36Sopenharmony_ci } 178462306a36Sopenharmony_ci 178562306a36Sopenharmony_ci i3c_bus_set_addr_slot_status(&master->bus, 178662306a36Sopenharmony_ci i3cboardinfo->init_dyn_addr, 178762306a36Sopenharmony_ci I3C_ADDR_SLOT_I3C_DEV); 178862306a36Sopenharmony_ci 178962306a36Sopenharmony_ci /* 179062306a36Sopenharmony_ci * Only try to create/attach devices that have a static 179162306a36Sopenharmony_ci * address. Other devices will be created/attached when 179262306a36Sopenharmony_ci * DAA happens, and the requested dynamic address will 179362306a36Sopenharmony_ci * be set using SETNEWDA once those devices become 179462306a36Sopenharmony_ci * addressable. 179562306a36Sopenharmony_ci */ 179662306a36Sopenharmony_ci 179762306a36Sopenharmony_ci if (i3cboardinfo->static_addr) 179862306a36Sopenharmony_ci i3c_master_early_i3c_dev_add(master, i3cboardinfo); 179962306a36Sopenharmony_ci } 180062306a36Sopenharmony_ci 180162306a36Sopenharmony_ci ret = i3c_master_do_daa(master); 180262306a36Sopenharmony_ci if (ret) 180362306a36Sopenharmony_ci goto err_rstdaa; 180462306a36Sopenharmony_ci 180562306a36Sopenharmony_ci return 0; 180662306a36Sopenharmony_ci 180762306a36Sopenharmony_cierr_rstdaa: 180862306a36Sopenharmony_ci i3c_master_rstdaa_locked(master, I3C_BROADCAST_ADDR); 180962306a36Sopenharmony_ci 181062306a36Sopenharmony_cierr_bus_cleanup: 181162306a36Sopenharmony_ci if (master->ops->bus_cleanup) 181262306a36Sopenharmony_ci master->ops->bus_cleanup(master); 181362306a36Sopenharmony_ci 181462306a36Sopenharmony_cierr_detach_devs: 181562306a36Sopenharmony_ci i3c_master_detach_free_devs(master); 181662306a36Sopenharmony_ci 181762306a36Sopenharmony_ci return ret; 181862306a36Sopenharmony_ci} 181962306a36Sopenharmony_ci 182062306a36Sopenharmony_cistatic void i3c_master_bus_cleanup(struct i3c_master_controller *master) 182162306a36Sopenharmony_ci{ 182262306a36Sopenharmony_ci if (master->ops->bus_cleanup) 182362306a36Sopenharmony_ci master->ops->bus_cleanup(master); 182462306a36Sopenharmony_ci 182562306a36Sopenharmony_ci i3c_master_detach_free_devs(master); 182662306a36Sopenharmony_ci} 182762306a36Sopenharmony_ci 182862306a36Sopenharmony_cistatic void i3c_master_attach_boardinfo(struct i3c_dev_desc *i3cdev) 182962306a36Sopenharmony_ci{ 183062306a36Sopenharmony_ci struct i3c_master_controller *master = i3cdev->common.master; 183162306a36Sopenharmony_ci struct i3c_dev_boardinfo *i3cboardinfo; 183262306a36Sopenharmony_ci 183362306a36Sopenharmony_ci list_for_each_entry(i3cboardinfo, &master->boardinfo.i3c, node) { 183462306a36Sopenharmony_ci if (i3cdev->info.pid != i3cboardinfo->pid) 183562306a36Sopenharmony_ci continue; 183662306a36Sopenharmony_ci 183762306a36Sopenharmony_ci i3cdev->boardinfo = i3cboardinfo; 183862306a36Sopenharmony_ci i3cdev->info.static_addr = i3cboardinfo->static_addr; 183962306a36Sopenharmony_ci return; 184062306a36Sopenharmony_ci } 184162306a36Sopenharmony_ci} 184262306a36Sopenharmony_ci 184362306a36Sopenharmony_cistatic struct i3c_dev_desc * 184462306a36Sopenharmony_cii3c_master_search_i3c_dev_duplicate(struct i3c_dev_desc *refdev) 184562306a36Sopenharmony_ci{ 184662306a36Sopenharmony_ci struct i3c_master_controller *master = i3c_dev_get_master(refdev); 184762306a36Sopenharmony_ci struct i3c_dev_desc *i3cdev; 184862306a36Sopenharmony_ci 184962306a36Sopenharmony_ci i3c_bus_for_each_i3cdev(&master->bus, i3cdev) { 185062306a36Sopenharmony_ci if (i3cdev != refdev && i3cdev->info.pid == refdev->info.pid) 185162306a36Sopenharmony_ci return i3cdev; 185262306a36Sopenharmony_ci } 185362306a36Sopenharmony_ci 185462306a36Sopenharmony_ci return NULL; 185562306a36Sopenharmony_ci} 185662306a36Sopenharmony_ci 185762306a36Sopenharmony_ci/** 185862306a36Sopenharmony_ci * i3c_master_add_i3c_dev_locked() - add an I3C slave to the bus 185962306a36Sopenharmony_ci * @master: master used to send frames on the bus 186062306a36Sopenharmony_ci * @addr: I3C slave dynamic address assigned to the device 186162306a36Sopenharmony_ci * 186262306a36Sopenharmony_ci * This function is instantiating an I3C device object and adding it to the 186362306a36Sopenharmony_ci * I3C device list. All device information are automatically retrieved using 186462306a36Sopenharmony_ci * standard CCC commands. 186562306a36Sopenharmony_ci * 186662306a36Sopenharmony_ci * The I3C device object is returned in case the master wants to attach 186762306a36Sopenharmony_ci * private data to it using i3c_dev_set_master_data(). 186862306a36Sopenharmony_ci * 186962306a36Sopenharmony_ci * This function must be called with the bus lock held in write mode. 187062306a36Sopenharmony_ci * 187162306a36Sopenharmony_ci * Return: a 0 in case of success, an negative error code otherwise. 187262306a36Sopenharmony_ci */ 187362306a36Sopenharmony_ciint i3c_master_add_i3c_dev_locked(struct i3c_master_controller *master, 187462306a36Sopenharmony_ci u8 addr) 187562306a36Sopenharmony_ci{ 187662306a36Sopenharmony_ci struct i3c_device_info info = { .dyn_addr = addr }; 187762306a36Sopenharmony_ci struct i3c_dev_desc *newdev, *olddev; 187862306a36Sopenharmony_ci u8 old_dyn_addr = addr, expected_dyn_addr; 187962306a36Sopenharmony_ci struct i3c_ibi_setup ibireq = { }; 188062306a36Sopenharmony_ci bool enable_ibi = false; 188162306a36Sopenharmony_ci int ret; 188262306a36Sopenharmony_ci 188362306a36Sopenharmony_ci if (!master) 188462306a36Sopenharmony_ci return -EINVAL; 188562306a36Sopenharmony_ci 188662306a36Sopenharmony_ci newdev = i3c_master_alloc_i3c_dev(master, &info); 188762306a36Sopenharmony_ci if (IS_ERR(newdev)) 188862306a36Sopenharmony_ci return PTR_ERR(newdev); 188962306a36Sopenharmony_ci 189062306a36Sopenharmony_ci ret = i3c_master_attach_i3c_dev(master, newdev); 189162306a36Sopenharmony_ci if (ret) 189262306a36Sopenharmony_ci goto err_free_dev; 189362306a36Sopenharmony_ci 189462306a36Sopenharmony_ci ret = i3c_master_retrieve_dev_info(newdev); 189562306a36Sopenharmony_ci if (ret) 189662306a36Sopenharmony_ci goto err_detach_dev; 189762306a36Sopenharmony_ci 189862306a36Sopenharmony_ci i3c_master_attach_boardinfo(newdev); 189962306a36Sopenharmony_ci 190062306a36Sopenharmony_ci olddev = i3c_master_search_i3c_dev_duplicate(newdev); 190162306a36Sopenharmony_ci if (olddev) { 190262306a36Sopenharmony_ci newdev->dev = olddev->dev; 190362306a36Sopenharmony_ci if (newdev->dev) 190462306a36Sopenharmony_ci newdev->dev->desc = newdev; 190562306a36Sopenharmony_ci 190662306a36Sopenharmony_ci /* 190762306a36Sopenharmony_ci * We need to restore the IBI state too, so let's save the 190862306a36Sopenharmony_ci * IBI information and try to restore them after olddev has 190962306a36Sopenharmony_ci * been detached+released and its IBI has been stopped and 191062306a36Sopenharmony_ci * the associated resources have been freed. 191162306a36Sopenharmony_ci */ 191262306a36Sopenharmony_ci mutex_lock(&olddev->ibi_lock); 191362306a36Sopenharmony_ci if (olddev->ibi) { 191462306a36Sopenharmony_ci ibireq.handler = olddev->ibi->handler; 191562306a36Sopenharmony_ci ibireq.max_payload_len = olddev->ibi->max_payload_len; 191662306a36Sopenharmony_ci ibireq.num_slots = olddev->ibi->num_slots; 191762306a36Sopenharmony_ci 191862306a36Sopenharmony_ci if (olddev->ibi->enabled) { 191962306a36Sopenharmony_ci enable_ibi = true; 192062306a36Sopenharmony_ci i3c_dev_disable_ibi_locked(olddev); 192162306a36Sopenharmony_ci } 192262306a36Sopenharmony_ci 192362306a36Sopenharmony_ci i3c_dev_free_ibi_locked(olddev); 192462306a36Sopenharmony_ci } 192562306a36Sopenharmony_ci mutex_unlock(&olddev->ibi_lock); 192662306a36Sopenharmony_ci 192762306a36Sopenharmony_ci old_dyn_addr = olddev->info.dyn_addr; 192862306a36Sopenharmony_ci 192962306a36Sopenharmony_ci i3c_master_detach_i3c_dev(olddev); 193062306a36Sopenharmony_ci i3c_master_free_i3c_dev(olddev); 193162306a36Sopenharmony_ci } 193262306a36Sopenharmony_ci 193362306a36Sopenharmony_ci /* 193462306a36Sopenharmony_ci * Depending on our previous state, the expected dynamic address might 193562306a36Sopenharmony_ci * differ: 193662306a36Sopenharmony_ci * - if the device already had a dynamic address assigned, let's try to 193762306a36Sopenharmony_ci * re-apply this one 193862306a36Sopenharmony_ci * - if the device did not have a dynamic address and the firmware 193962306a36Sopenharmony_ci * requested a specific address, pick this one 194062306a36Sopenharmony_ci * - in any other case, keep the address automatically assigned by the 194162306a36Sopenharmony_ci * master 194262306a36Sopenharmony_ci */ 194362306a36Sopenharmony_ci if (old_dyn_addr && old_dyn_addr != newdev->info.dyn_addr) 194462306a36Sopenharmony_ci expected_dyn_addr = old_dyn_addr; 194562306a36Sopenharmony_ci else if (newdev->boardinfo && newdev->boardinfo->init_dyn_addr) 194662306a36Sopenharmony_ci expected_dyn_addr = newdev->boardinfo->init_dyn_addr; 194762306a36Sopenharmony_ci else 194862306a36Sopenharmony_ci expected_dyn_addr = newdev->info.dyn_addr; 194962306a36Sopenharmony_ci 195062306a36Sopenharmony_ci if (newdev->info.dyn_addr != expected_dyn_addr) { 195162306a36Sopenharmony_ci /* 195262306a36Sopenharmony_ci * Try to apply the expected dynamic address. If it fails, keep 195362306a36Sopenharmony_ci * the address assigned by the master. 195462306a36Sopenharmony_ci */ 195562306a36Sopenharmony_ci ret = i3c_master_setnewda_locked(master, 195662306a36Sopenharmony_ci newdev->info.dyn_addr, 195762306a36Sopenharmony_ci expected_dyn_addr); 195862306a36Sopenharmony_ci if (!ret) { 195962306a36Sopenharmony_ci old_dyn_addr = newdev->info.dyn_addr; 196062306a36Sopenharmony_ci newdev->info.dyn_addr = expected_dyn_addr; 196162306a36Sopenharmony_ci i3c_master_reattach_i3c_dev(newdev, old_dyn_addr); 196262306a36Sopenharmony_ci } else { 196362306a36Sopenharmony_ci dev_err(&master->dev, 196462306a36Sopenharmony_ci "Failed to assign reserved/old address to device %d%llx", 196562306a36Sopenharmony_ci master->bus.id, newdev->info.pid); 196662306a36Sopenharmony_ci } 196762306a36Sopenharmony_ci } 196862306a36Sopenharmony_ci 196962306a36Sopenharmony_ci /* 197062306a36Sopenharmony_ci * Now is time to try to restore the IBI setup. If we're lucky, 197162306a36Sopenharmony_ci * everything works as before, otherwise, all we can do is complain. 197262306a36Sopenharmony_ci * FIXME: maybe we should add callback to inform the driver that it 197362306a36Sopenharmony_ci * should request the IBI again instead of trying to hide that from 197462306a36Sopenharmony_ci * him. 197562306a36Sopenharmony_ci */ 197662306a36Sopenharmony_ci if (ibireq.handler) { 197762306a36Sopenharmony_ci mutex_lock(&newdev->ibi_lock); 197862306a36Sopenharmony_ci ret = i3c_dev_request_ibi_locked(newdev, &ibireq); 197962306a36Sopenharmony_ci if (ret) { 198062306a36Sopenharmony_ci dev_err(&master->dev, 198162306a36Sopenharmony_ci "Failed to request IBI on device %d-%llx", 198262306a36Sopenharmony_ci master->bus.id, newdev->info.pid); 198362306a36Sopenharmony_ci } else if (enable_ibi) { 198462306a36Sopenharmony_ci ret = i3c_dev_enable_ibi_locked(newdev); 198562306a36Sopenharmony_ci if (ret) 198662306a36Sopenharmony_ci dev_err(&master->dev, 198762306a36Sopenharmony_ci "Failed to re-enable IBI on device %d-%llx", 198862306a36Sopenharmony_ci master->bus.id, newdev->info.pid); 198962306a36Sopenharmony_ci } 199062306a36Sopenharmony_ci mutex_unlock(&newdev->ibi_lock); 199162306a36Sopenharmony_ci } 199262306a36Sopenharmony_ci 199362306a36Sopenharmony_ci return 0; 199462306a36Sopenharmony_ci 199562306a36Sopenharmony_cierr_detach_dev: 199662306a36Sopenharmony_ci if (newdev->dev && newdev->dev->desc) 199762306a36Sopenharmony_ci newdev->dev->desc = NULL; 199862306a36Sopenharmony_ci 199962306a36Sopenharmony_ci i3c_master_detach_i3c_dev(newdev); 200062306a36Sopenharmony_ci 200162306a36Sopenharmony_cierr_free_dev: 200262306a36Sopenharmony_ci i3c_master_free_i3c_dev(newdev); 200362306a36Sopenharmony_ci 200462306a36Sopenharmony_ci return ret; 200562306a36Sopenharmony_ci} 200662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(i3c_master_add_i3c_dev_locked); 200762306a36Sopenharmony_ci 200862306a36Sopenharmony_ci#define OF_I3C_REG1_IS_I2C_DEV BIT(31) 200962306a36Sopenharmony_ci 201062306a36Sopenharmony_cistatic int 201162306a36Sopenharmony_ciof_i3c_master_add_i2c_boardinfo(struct i3c_master_controller *master, 201262306a36Sopenharmony_ci struct device_node *node, u32 *reg) 201362306a36Sopenharmony_ci{ 201462306a36Sopenharmony_ci struct i2c_dev_boardinfo *boardinfo; 201562306a36Sopenharmony_ci struct device *dev = &master->dev; 201662306a36Sopenharmony_ci int ret; 201762306a36Sopenharmony_ci 201862306a36Sopenharmony_ci boardinfo = devm_kzalloc(dev, sizeof(*boardinfo), GFP_KERNEL); 201962306a36Sopenharmony_ci if (!boardinfo) 202062306a36Sopenharmony_ci return -ENOMEM; 202162306a36Sopenharmony_ci 202262306a36Sopenharmony_ci ret = of_i2c_get_board_info(dev, node, &boardinfo->base); 202362306a36Sopenharmony_ci if (ret) 202462306a36Sopenharmony_ci return ret; 202562306a36Sopenharmony_ci 202662306a36Sopenharmony_ci /* 202762306a36Sopenharmony_ci * The I3C Specification does not clearly say I2C devices with 10-bit 202862306a36Sopenharmony_ci * address are supported. These devices can't be passed properly through 202962306a36Sopenharmony_ci * DEFSLVS command. 203062306a36Sopenharmony_ci */ 203162306a36Sopenharmony_ci if (boardinfo->base.flags & I2C_CLIENT_TEN) { 203262306a36Sopenharmony_ci dev_err(dev, "I2C device with 10 bit address not supported."); 203362306a36Sopenharmony_ci return -ENOTSUPP; 203462306a36Sopenharmony_ci } 203562306a36Sopenharmony_ci 203662306a36Sopenharmony_ci /* LVR is encoded in reg[2]. */ 203762306a36Sopenharmony_ci boardinfo->lvr = reg[2]; 203862306a36Sopenharmony_ci 203962306a36Sopenharmony_ci list_add_tail(&boardinfo->node, &master->boardinfo.i2c); 204062306a36Sopenharmony_ci of_node_get(node); 204162306a36Sopenharmony_ci 204262306a36Sopenharmony_ci return 0; 204362306a36Sopenharmony_ci} 204462306a36Sopenharmony_ci 204562306a36Sopenharmony_cistatic int 204662306a36Sopenharmony_ciof_i3c_master_add_i3c_boardinfo(struct i3c_master_controller *master, 204762306a36Sopenharmony_ci struct device_node *node, u32 *reg) 204862306a36Sopenharmony_ci{ 204962306a36Sopenharmony_ci struct i3c_dev_boardinfo *boardinfo; 205062306a36Sopenharmony_ci struct device *dev = &master->dev; 205162306a36Sopenharmony_ci enum i3c_addr_slot_status addrstatus; 205262306a36Sopenharmony_ci u32 init_dyn_addr = 0; 205362306a36Sopenharmony_ci 205462306a36Sopenharmony_ci boardinfo = devm_kzalloc(dev, sizeof(*boardinfo), GFP_KERNEL); 205562306a36Sopenharmony_ci if (!boardinfo) 205662306a36Sopenharmony_ci return -ENOMEM; 205762306a36Sopenharmony_ci 205862306a36Sopenharmony_ci if (reg[0]) { 205962306a36Sopenharmony_ci if (reg[0] > I3C_MAX_ADDR) 206062306a36Sopenharmony_ci return -EINVAL; 206162306a36Sopenharmony_ci 206262306a36Sopenharmony_ci addrstatus = i3c_bus_get_addr_slot_status(&master->bus, 206362306a36Sopenharmony_ci reg[0]); 206462306a36Sopenharmony_ci if (addrstatus != I3C_ADDR_SLOT_FREE) 206562306a36Sopenharmony_ci return -EINVAL; 206662306a36Sopenharmony_ci } 206762306a36Sopenharmony_ci 206862306a36Sopenharmony_ci boardinfo->static_addr = reg[0]; 206962306a36Sopenharmony_ci 207062306a36Sopenharmony_ci if (!of_property_read_u32(node, "assigned-address", &init_dyn_addr)) { 207162306a36Sopenharmony_ci if (init_dyn_addr > I3C_MAX_ADDR) 207262306a36Sopenharmony_ci return -EINVAL; 207362306a36Sopenharmony_ci 207462306a36Sopenharmony_ci addrstatus = i3c_bus_get_addr_slot_status(&master->bus, 207562306a36Sopenharmony_ci init_dyn_addr); 207662306a36Sopenharmony_ci if (addrstatus != I3C_ADDR_SLOT_FREE) 207762306a36Sopenharmony_ci return -EINVAL; 207862306a36Sopenharmony_ci } 207962306a36Sopenharmony_ci 208062306a36Sopenharmony_ci boardinfo->pid = ((u64)reg[1] << 32) | reg[2]; 208162306a36Sopenharmony_ci 208262306a36Sopenharmony_ci if ((boardinfo->pid & GENMASK_ULL(63, 48)) || 208362306a36Sopenharmony_ci I3C_PID_RND_LOWER_32BITS(boardinfo->pid)) 208462306a36Sopenharmony_ci return -EINVAL; 208562306a36Sopenharmony_ci 208662306a36Sopenharmony_ci boardinfo->init_dyn_addr = init_dyn_addr; 208762306a36Sopenharmony_ci boardinfo->of_node = of_node_get(node); 208862306a36Sopenharmony_ci list_add_tail(&boardinfo->node, &master->boardinfo.i3c); 208962306a36Sopenharmony_ci 209062306a36Sopenharmony_ci return 0; 209162306a36Sopenharmony_ci} 209262306a36Sopenharmony_ci 209362306a36Sopenharmony_cistatic int of_i3c_master_add_dev(struct i3c_master_controller *master, 209462306a36Sopenharmony_ci struct device_node *node) 209562306a36Sopenharmony_ci{ 209662306a36Sopenharmony_ci u32 reg[3]; 209762306a36Sopenharmony_ci int ret; 209862306a36Sopenharmony_ci 209962306a36Sopenharmony_ci if (!master || !node) 210062306a36Sopenharmony_ci return -EINVAL; 210162306a36Sopenharmony_ci 210262306a36Sopenharmony_ci ret = of_property_read_u32_array(node, "reg", reg, ARRAY_SIZE(reg)); 210362306a36Sopenharmony_ci if (ret) 210462306a36Sopenharmony_ci return ret; 210562306a36Sopenharmony_ci 210662306a36Sopenharmony_ci /* 210762306a36Sopenharmony_ci * The manufacturer ID can't be 0. If reg[1] == 0 that means we're 210862306a36Sopenharmony_ci * dealing with an I2C device. 210962306a36Sopenharmony_ci */ 211062306a36Sopenharmony_ci if (!reg[1]) 211162306a36Sopenharmony_ci ret = of_i3c_master_add_i2c_boardinfo(master, node, reg); 211262306a36Sopenharmony_ci else 211362306a36Sopenharmony_ci ret = of_i3c_master_add_i3c_boardinfo(master, node, reg); 211462306a36Sopenharmony_ci 211562306a36Sopenharmony_ci return ret; 211662306a36Sopenharmony_ci} 211762306a36Sopenharmony_ci 211862306a36Sopenharmony_cistatic int of_populate_i3c_bus(struct i3c_master_controller *master) 211962306a36Sopenharmony_ci{ 212062306a36Sopenharmony_ci struct device *dev = &master->dev; 212162306a36Sopenharmony_ci struct device_node *i3cbus_np = dev->of_node; 212262306a36Sopenharmony_ci struct device_node *node; 212362306a36Sopenharmony_ci int ret; 212462306a36Sopenharmony_ci u32 val; 212562306a36Sopenharmony_ci 212662306a36Sopenharmony_ci if (!i3cbus_np) 212762306a36Sopenharmony_ci return 0; 212862306a36Sopenharmony_ci 212962306a36Sopenharmony_ci for_each_available_child_of_node(i3cbus_np, node) { 213062306a36Sopenharmony_ci ret = of_i3c_master_add_dev(master, node); 213162306a36Sopenharmony_ci if (ret) { 213262306a36Sopenharmony_ci of_node_put(node); 213362306a36Sopenharmony_ci return ret; 213462306a36Sopenharmony_ci } 213562306a36Sopenharmony_ci } 213662306a36Sopenharmony_ci 213762306a36Sopenharmony_ci /* 213862306a36Sopenharmony_ci * The user might want to limit I2C and I3C speed in case some devices 213962306a36Sopenharmony_ci * on the bus are not supporting typical rates, or if the bus topology 214062306a36Sopenharmony_ci * prevents it from using max possible rate. 214162306a36Sopenharmony_ci */ 214262306a36Sopenharmony_ci if (!of_property_read_u32(i3cbus_np, "i2c-scl-hz", &val)) 214362306a36Sopenharmony_ci master->bus.scl_rate.i2c = val; 214462306a36Sopenharmony_ci 214562306a36Sopenharmony_ci if (!of_property_read_u32(i3cbus_np, "i3c-scl-hz", &val)) 214662306a36Sopenharmony_ci master->bus.scl_rate.i3c = val; 214762306a36Sopenharmony_ci 214862306a36Sopenharmony_ci return 0; 214962306a36Sopenharmony_ci} 215062306a36Sopenharmony_ci 215162306a36Sopenharmony_cistatic int i3c_master_i2c_adapter_xfer(struct i2c_adapter *adap, 215262306a36Sopenharmony_ci struct i2c_msg *xfers, int nxfers) 215362306a36Sopenharmony_ci{ 215462306a36Sopenharmony_ci struct i3c_master_controller *master = i2c_adapter_to_i3c_master(adap); 215562306a36Sopenharmony_ci struct i2c_dev_desc *dev; 215662306a36Sopenharmony_ci int i, ret; 215762306a36Sopenharmony_ci u16 addr; 215862306a36Sopenharmony_ci 215962306a36Sopenharmony_ci if (!xfers || !master || nxfers <= 0) 216062306a36Sopenharmony_ci return -EINVAL; 216162306a36Sopenharmony_ci 216262306a36Sopenharmony_ci if (!master->ops->i2c_xfers) 216362306a36Sopenharmony_ci return -ENOTSUPP; 216462306a36Sopenharmony_ci 216562306a36Sopenharmony_ci /* Doing transfers to different devices is not supported. */ 216662306a36Sopenharmony_ci addr = xfers[0].addr; 216762306a36Sopenharmony_ci for (i = 1; i < nxfers; i++) { 216862306a36Sopenharmony_ci if (addr != xfers[i].addr) 216962306a36Sopenharmony_ci return -ENOTSUPP; 217062306a36Sopenharmony_ci } 217162306a36Sopenharmony_ci 217262306a36Sopenharmony_ci i3c_bus_normaluse_lock(&master->bus); 217362306a36Sopenharmony_ci dev = i3c_master_find_i2c_dev_by_addr(master, addr); 217462306a36Sopenharmony_ci if (!dev) 217562306a36Sopenharmony_ci ret = -ENOENT; 217662306a36Sopenharmony_ci else 217762306a36Sopenharmony_ci ret = master->ops->i2c_xfers(dev, xfers, nxfers); 217862306a36Sopenharmony_ci i3c_bus_normaluse_unlock(&master->bus); 217962306a36Sopenharmony_ci 218062306a36Sopenharmony_ci return ret ? ret : nxfers; 218162306a36Sopenharmony_ci} 218262306a36Sopenharmony_ci 218362306a36Sopenharmony_cistatic u32 i3c_master_i2c_funcs(struct i2c_adapter *adapter) 218462306a36Sopenharmony_ci{ 218562306a36Sopenharmony_ci return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C; 218662306a36Sopenharmony_ci} 218762306a36Sopenharmony_ci 218862306a36Sopenharmony_cistatic u8 i3c_master_i2c_get_lvr(struct i2c_client *client) 218962306a36Sopenharmony_ci{ 219062306a36Sopenharmony_ci /* Fall back to no spike filters and FM bus mode. */ 219162306a36Sopenharmony_ci u8 lvr = I3C_LVR_I2C_INDEX(2) | I3C_LVR_I2C_FM_MODE; 219262306a36Sopenharmony_ci 219362306a36Sopenharmony_ci if (client->dev.of_node) { 219462306a36Sopenharmony_ci u32 reg[3]; 219562306a36Sopenharmony_ci 219662306a36Sopenharmony_ci if (!of_property_read_u32_array(client->dev.of_node, "reg", 219762306a36Sopenharmony_ci reg, ARRAY_SIZE(reg))) 219862306a36Sopenharmony_ci lvr = reg[2]; 219962306a36Sopenharmony_ci } 220062306a36Sopenharmony_ci 220162306a36Sopenharmony_ci return lvr; 220262306a36Sopenharmony_ci} 220362306a36Sopenharmony_ci 220462306a36Sopenharmony_cistatic int i3c_master_i2c_attach(struct i2c_adapter *adap, struct i2c_client *client) 220562306a36Sopenharmony_ci{ 220662306a36Sopenharmony_ci struct i3c_master_controller *master = i2c_adapter_to_i3c_master(adap); 220762306a36Sopenharmony_ci enum i3c_addr_slot_status status; 220862306a36Sopenharmony_ci struct i2c_dev_desc *i2cdev; 220962306a36Sopenharmony_ci int ret; 221062306a36Sopenharmony_ci 221162306a36Sopenharmony_ci /* Already added by board info? */ 221262306a36Sopenharmony_ci if (i3c_master_find_i2c_dev_by_addr(master, client->addr)) 221362306a36Sopenharmony_ci return 0; 221462306a36Sopenharmony_ci 221562306a36Sopenharmony_ci status = i3c_bus_get_addr_slot_status(&master->bus, client->addr); 221662306a36Sopenharmony_ci if (status != I3C_ADDR_SLOT_FREE) 221762306a36Sopenharmony_ci return -EBUSY; 221862306a36Sopenharmony_ci 221962306a36Sopenharmony_ci i3c_bus_set_addr_slot_status(&master->bus, client->addr, 222062306a36Sopenharmony_ci I3C_ADDR_SLOT_I2C_DEV); 222162306a36Sopenharmony_ci 222262306a36Sopenharmony_ci i2cdev = i3c_master_alloc_i2c_dev(master, client->addr, 222362306a36Sopenharmony_ci i3c_master_i2c_get_lvr(client)); 222462306a36Sopenharmony_ci if (IS_ERR(i2cdev)) { 222562306a36Sopenharmony_ci ret = PTR_ERR(i2cdev); 222662306a36Sopenharmony_ci goto out_clear_status; 222762306a36Sopenharmony_ci } 222862306a36Sopenharmony_ci 222962306a36Sopenharmony_ci ret = i3c_master_attach_i2c_dev(master, i2cdev); 223062306a36Sopenharmony_ci if (ret) 223162306a36Sopenharmony_ci goto out_free_dev; 223262306a36Sopenharmony_ci 223362306a36Sopenharmony_ci return 0; 223462306a36Sopenharmony_ci 223562306a36Sopenharmony_ciout_free_dev: 223662306a36Sopenharmony_ci i3c_master_free_i2c_dev(i2cdev); 223762306a36Sopenharmony_ciout_clear_status: 223862306a36Sopenharmony_ci i3c_bus_set_addr_slot_status(&master->bus, client->addr, 223962306a36Sopenharmony_ci I3C_ADDR_SLOT_FREE); 224062306a36Sopenharmony_ci 224162306a36Sopenharmony_ci return ret; 224262306a36Sopenharmony_ci} 224362306a36Sopenharmony_ci 224462306a36Sopenharmony_cistatic int i3c_master_i2c_detach(struct i2c_adapter *adap, struct i2c_client *client) 224562306a36Sopenharmony_ci{ 224662306a36Sopenharmony_ci struct i3c_master_controller *master = i2c_adapter_to_i3c_master(adap); 224762306a36Sopenharmony_ci struct i2c_dev_desc *dev; 224862306a36Sopenharmony_ci 224962306a36Sopenharmony_ci dev = i3c_master_find_i2c_dev_by_addr(master, client->addr); 225062306a36Sopenharmony_ci if (!dev) 225162306a36Sopenharmony_ci return -ENODEV; 225262306a36Sopenharmony_ci 225362306a36Sopenharmony_ci i3c_master_detach_i2c_dev(dev); 225462306a36Sopenharmony_ci i3c_bus_set_addr_slot_status(&master->bus, dev->addr, 225562306a36Sopenharmony_ci I3C_ADDR_SLOT_FREE); 225662306a36Sopenharmony_ci i3c_master_free_i2c_dev(dev); 225762306a36Sopenharmony_ci 225862306a36Sopenharmony_ci return 0; 225962306a36Sopenharmony_ci} 226062306a36Sopenharmony_ci 226162306a36Sopenharmony_cistatic const struct i2c_algorithm i3c_master_i2c_algo = { 226262306a36Sopenharmony_ci .master_xfer = i3c_master_i2c_adapter_xfer, 226362306a36Sopenharmony_ci .functionality = i3c_master_i2c_funcs, 226462306a36Sopenharmony_ci}; 226562306a36Sopenharmony_ci 226662306a36Sopenharmony_cistatic int i3c_i2c_notifier_call(struct notifier_block *nb, unsigned long action, 226762306a36Sopenharmony_ci void *data) 226862306a36Sopenharmony_ci{ 226962306a36Sopenharmony_ci struct i2c_adapter *adap; 227062306a36Sopenharmony_ci struct i2c_client *client; 227162306a36Sopenharmony_ci struct device *dev = data; 227262306a36Sopenharmony_ci struct i3c_master_controller *master; 227362306a36Sopenharmony_ci int ret; 227462306a36Sopenharmony_ci 227562306a36Sopenharmony_ci if (dev->type != &i2c_client_type) 227662306a36Sopenharmony_ci return 0; 227762306a36Sopenharmony_ci 227862306a36Sopenharmony_ci client = to_i2c_client(dev); 227962306a36Sopenharmony_ci adap = client->adapter; 228062306a36Sopenharmony_ci 228162306a36Sopenharmony_ci if (adap->algo != &i3c_master_i2c_algo) 228262306a36Sopenharmony_ci return 0; 228362306a36Sopenharmony_ci 228462306a36Sopenharmony_ci master = i2c_adapter_to_i3c_master(adap); 228562306a36Sopenharmony_ci 228662306a36Sopenharmony_ci i3c_bus_maintenance_lock(&master->bus); 228762306a36Sopenharmony_ci switch (action) { 228862306a36Sopenharmony_ci case BUS_NOTIFY_ADD_DEVICE: 228962306a36Sopenharmony_ci ret = i3c_master_i2c_attach(adap, client); 229062306a36Sopenharmony_ci break; 229162306a36Sopenharmony_ci case BUS_NOTIFY_DEL_DEVICE: 229262306a36Sopenharmony_ci ret = i3c_master_i2c_detach(adap, client); 229362306a36Sopenharmony_ci break; 229462306a36Sopenharmony_ci } 229562306a36Sopenharmony_ci i3c_bus_maintenance_unlock(&master->bus); 229662306a36Sopenharmony_ci 229762306a36Sopenharmony_ci return ret; 229862306a36Sopenharmony_ci} 229962306a36Sopenharmony_ci 230062306a36Sopenharmony_cistatic struct notifier_block i2cdev_notifier = { 230162306a36Sopenharmony_ci .notifier_call = i3c_i2c_notifier_call, 230262306a36Sopenharmony_ci}; 230362306a36Sopenharmony_ci 230462306a36Sopenharmony_cistatic int i3c_master_i2c_adapter_init(struct i3c_master_controller *master) 230562306a36Sopenharmony_ci{ 230662306a36Sopenharmony_ci struct i2c_adapter *adap = i3c_master_to_i2c_adapter(master); 230762306a36Sopenharmony_ci struct i2c_dev_desc *i2cdev; 230862306a36Sopenharmony_ci struct i2c_dev_boardinfo *i2cboardinfo; 230962306a36Sopenharmony_ci int ret; 231062306a36Sopenharmony_ci 231162306a36Sopenharmony_ci adap->dev.parent = master->dev.parent; 231262306a36Sopenharmony_ci adap->owner = master->dev.parent->driver->owner; 231362306a36Sopenharmony_ci adap->algo = &i3c_master_i2c_algo; 231462306a36Sopenharmony_ci strncpy(adap->name, dev_name(master->dev.parent), sizeof(adap->name)); 231562306a36Sopenharmony_ci 231662306a36Sopenharmony_ci /* FIXME: Should we allow i3c masters to override these values? */ 231762306a36Sopenharmony_ci adap->timeout = 1000; 231862306a36Sopenharmony_ci adap->retries = 3; 231962306a36Sopenharmony_ci 232062306a36Sopenharmony_ci ret = i2c_add_adapter(adap); 232162306a36Sopenharmony_ci if (ret) 232262306a36Sopenharmony_ci return ret; 232362306a36Sopenharmony_ci 232462306a36Sopenharmony_ci /* 232562306a36Sopenharmony_ci * We silently ignore failures here. The bus should keep working 232662306a36Sopenharmony_ci * correctly even if one or more i2c devices are not registered. 232762306a36Sopenharmony_ci */ 232862306a36Sopenharmony_ci list_for_each_entry(i2cboardinfo, &master->boardinfo.i2c, node) { 232962306a36Sopenharmony_ci i2cdev = i3c_master_find_i2c_dev_by_addr(master, 233062306a36Sopenharmony_ci i2cboardinfo->base.addr); 233162306a36Sopenharmony_ci if (WARN_ON(!i2cdev)) 233262306a36Sopenharmony_ci continue; 233362306a36Sopenharmony_ci i2cdev->dev = i2c_new_client_device(adap, &i2cboardinfo->base); 233462306a36Sopenharmony_ci } 233562306a36Sopenharmony_ci 233662306a36Sopenharmony_ci return 0; 233762306a36Sopenharmony_ci} 233862306a36Sopenharmony_ci 233962306a36Sopenharmony_cistatic void i3c_master_i2c_adapter_cleanup(struct i3c_master_controller *master) 234062306a36Sopenharmony_ci{ 234162306a36Sopenharmony_ci struct i2c_dev_desc *i2cdev; 234262306a36Sopenharmony_ci 234362306a36Sopenharmony_ci i2c_del_adapter(&master->i2c); 234462306a36Sopenharmony_ci 234562306a36Sopenharmony_ci i3c_bus_for_each_i2cdev(&master->bus, i2cdev) 234662306a36Sopenharmony_ci i2cdev->dev = NULL; 234762306a36Sopenharmony_ci} 234862306a36Sopenharmony_ci 234962306a36Sopenharmony_cistatic void i3c_master_unregister_i3c_devs(struct i3c_master_controller *master) 235062306a36Sopenharmony_ci{ 235162306a36Sopenharmony_ci struct i3c_dev_desc *i3cdev; 235262306a36Sopenharmony_ci 235362306a36Sopenharmony_ci i3c_bus_for_each_i3cdev(&master->bus, i3cdev) { 235462306a36Sopenharmony_ci if (!i3cdev->dev) 235562306a36Sopenharmony_ci continue; 235662306a36Sopenharmony_ci 235762306a36Sopenharmony_ci i3cdev->dev->desc = NULL; 235862306a36Sopenharmony_ci if (device_is_registered(&i3cdev->dev->dev)) 235962306a36Sopenharmony_ci device_unregister(&i3cdev->dev->dev); 236062306a36Sopenharmony_ci else 236162306a36Sopenharmony_ci put_device(&i3cdev->dev->dev); 236262306a36Sopenharmony_ci i3cdev->dev = NULL; 236362306a36Sopenharmony_ci } 236462306a36Sopenharmony_ci} 236562306a36Sopenharmony_ci 236662306a36Sopenharmony_ci/** 236762306a36Sopenharmony_ci * i3c_master_queue_ibi() - Queue an IBI 236862306a36Sopenharmony_ci * @dev: the device this IBI is coming from 236962306a36Sopenharmony_ci * @slot: the IBI slot used to store the payload 237062306a36Sopenharmony_ci * 237162306a36Sopenharmony_ci * Queue an IBI to the controller workqueue. The IBI handler attached to 237262306a36Sopenharmony_ci * the dev will be called from a workqueue context. 237362306a36Sopenharmony_ci */ 237462306a36Sopenharmony_civoid i3c_master_queue_ibi(struct i3c_dev_desc *dev, struct i3c_ibi_slot *slot) 237562306a36Sopenharmony_ci{ 237662306a36Sopenharmony_ci atomic_inc(&dev->ibi->pending_ibis); 237762306a36Sopenharmony_ci queue_work(dev->common.master->wq, &slot->work); 237862306a36Sopenharmony_ci} 237962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(i3c_master_queue_ibi); 238062306a36Sopenharmony_ci 238162306a36Sopenharmony_cistatic void i3c_master_handle_ibi(struct work_struct *work) 238262306a36Sopenharmony_ci{ 238362306a36Sopenharmony_ci struct i3c_ibi_slot *slot = container_of(work, struct i3c_ibi_slot, 238462306a36Sopenharmony_ci work); 238562306a36Sopenharmony_ci struct i3c_dev_desc *dev = slot->dev; 238662306a36Sopenharmony_ci struct i3c_master_controller *master = i3c_dev_get_master(dev); 238762306a36Sopenharmony_ci struct i3c_ibi_payload payload; 238862306a36Sopenharmony_ci 238962306a36Sopenharmony_ci payload.data = slot->data; 239062306a36Sopenharmony_ci payload.len = slot->len; 239162306a36Sopenharmony_ci 239262306a36Sopenharmony_ci if (dev->dev) 239362306a36Sopenharmony_ci dev->ibi->handler(dev->dev, &payload); 239462306a36Sopenharmony_ci 239562306a36Sopenharmony_ci master->ops->recycle_ibi_slot(dev, slot); 239662306a36Sopenharmony_ci if (atomic_dec_and_test(&dev->ibi->pending_ibis)) 239762306a36Sopenharmony_ci complete(&dev->ibi->all_ibis_handled); 239862306a36Sopenharmony_ci} 239962306a36Sopenharmony_ci 240062306a36Sopenharmony_cistatic void i3c_master_init_ibi_slot(struct i3c_dev_desc *dev, 240162306a36Sopenharmony_ci struct i3c_ibi_slot *slot) 240262306a36Sopenharmony_ci{ 240362306a36Sopenharmony_ci slot->dev = dev; 240462306a36Sopenharmony_ci INIT_WORK(&slot->work, i3c_master_handle_ibi); 240562306a36Sopenharmony_ci} 240662306a36Sopenharmony_ci 240762306a36Sopenharmony_cistruct i3c_generic_ibi_slot { 240862306a36Sopenharmony_ci struct list_head node; 240962306a36Sopenharmony_ci struct i3c_ibi_slot base; 241062306a36Sopenharmony_ci}; 241162306a36Sopenharmony_ci 241262306a36Sopenharmony_cistruct i3c_generic_ibi_pool { 241362306a36Sopenharmony_ci spinlock_t lock; 241462306a36Sopenharmony_ci unsigned int num_slots; 241562306a36Sopenharmony_ci struct i3c_generic_ibi_slot *slots; 241662306a36Sopenharmony_ci void *payload_buf; 241762306a36Sopenharmony_ci struct list_head free_slots; 241862306a36Sopenharmony_ci struct list_head pending; 241962306a36Sopenharmony_ci}; 242062306a36Sopenharmony_ci 242162306a36Sopenharmony_ci/** 242262306a36Sopenharmony_ci * i3c_generic_ibi_free_pool() - Free a generic IBI pool 242362306a36Sopenharmony_ci * @pool: the IBI pool to free 242462306a36Sopenharmony_ci * 242562306a36Sopenharmony_ci * Free all IBI slots allated by a generic IBI pool. 242662306a36Sopenharmony_ci */ 242762306a36Sopenharmony_civoid i3c_generic_ibi_free_pool(struct i3c_generic_ibi_pool *pool) 242862306a36Sopenharmony_ci{ 242962306a36Sopenharmony_ci struct i3c_generic_ibi_slot *slot; 243062306a36Sopenharmony_ci unsigned int nslots = 0; 243162306a36Sopenharmony_ci 243262306a36Sopenharmony_ci while (!list_empty(&pool->free_slots)) { 243362306a36Sopenharmony_ci slot = list_first_entry(&pool->free_slots, 243462306a36Sopenharmony_ci struct i3c_generic_ibi_slot, node); 243562306a36Sopenharmony_ci list_del(&slot->node); 243662306a36Sopenharmony_ci nslots++; 243762306a36Sopenharmony_ci } 243862306a36Sopenharmony_ci 243962306a36Sopenharmony_ci /* 244062306a36Sopenharmony_ci * If the number of freed slots is not equal to the number of allocated 244162306a36Sopenharmony_ci * slots we have a leak somewhere. 244262306a36Sopenharmony_ci */ 244362306a36Sopenharmony_ci WARN_ON(nslots != pool->num_slots); 244462306a36Sopenharmony_ci 244562306a36Sopenharmony_ci kfree(pool->payload_buf); 244662306a36Sopenharmony_ci kfree(pool->slots); 244762306a36Sopenharmony_ci kfree(pool); 244862306a36Sopenharmony_ci} 244962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(i3c_generic_ibi_free_pool); 245062306a36Sopenharmony_ci 245162306a36Sopenharmony_ci/** 245262306a36Sopenharmony_ci * i3c_generic_ibi_alloc_pool() - Create a generic IBI pool 245362306a36Sopenharmony_ci * @dev: the device this pool will be used for 245462306a36Sopenharmony_ci * @req: IBI setup request describing what the device driver expects 245562306a36Sopenharmony_ci * 245662306a36Sopenharmony_ci * Create a generic IBI pool based on the information provided in @req. 245762306a36Sopenharmony_ci * 245862306a36Sopenharmony_ci * Return: a valid IBI pool in case of success, an ERR_PTR() otherwise. 245962306a36Sopenharmony_ci */ 246062306a36Sopenharmony_cistruct i3c_generic_ibi_pool * 246162306a36Sopenharmony_cii3c_generic_ibi_alloc_pool(struct i3c_dev_desc *dev, 246262306a36Sopenharmony_ci const struct i3c_ibi_setup *req) 246362306a36Sopenharmony_ci{ 246462306a36Sopenharmony_ci struct i3c_generic_ibi_pool *pool; 246562306a36Sopenharmony_ci struct i3c_generic_ibi_slot *slot; 246662306a36Sopenharmony_ci unsigned int i; 246762306a36Sopenharmony_ci int ret; 246862306a36Sopenharmony_ci 246962306a36Sopenharmony_ci pool = kzalloc(sizeof(*pool), GFP_KERNEL); 247062306a36Sopenharmony_ci if (!pool) 247162306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 247262306a36Sopenharmony_ci 247362306a36Sopenharmony_ci spin_lock_init(&pool->lock); 247462306a36Sopenharmony_ci INIT_LIST_HEAD(&pool->free_slots); 247562306a36Sopenharmony_ci INIT_LIST_HEAD(&pool->pending); 247662306a36Sopenharmony_ci 247762306a36Sopenharmony_ci pool->slots = kcalloc(req->num_slots, sizeof(*slot), GFP_KERNEL); 247862306a36Sopenharmony_ci if (!pool->slots) { 247962306a36Sopenharmony_ci ret = -ENOMEM; 248062306a36Sopenharmony_ci goto err_free_pool; 248162306a36Sopenharmony_ci } 248262306a36Sopenharmony_ci 248362306a36Sopenharmony_ci if (req->max_payload_len) { 248462306a36Sopenharmony_ci pool->payload_buf = kcalloc(req->num_slots, 248562306a36Sopenharmony_ci req->max_payload_len, GFP_KERNEL); 248662306a36Sopenharmony_ci if (!pool->payload_buf) { 248762306a36Sopenharmony_ci ret = -ENOMEM; 248862306a36Sopenharmony_ci goto err_free_pool; 248962306a36Sopenharmony_ci } 249062306a36Sopenharmony_ci } 249162306a36Sopenharmony_ci 249262306a36Sopenharmony_ci for (i = 0; i < req->num_slots; i++) { 249362306a36Sopenharmony_ci slot = &pool->slots[i]; 249462306a36Sopenharmony_ci i3c_master_init_ibi_slot(dev, &slot->base); 249562306a36Sopenharmony_ci 249662306a36Sopenharmony_ci if (req->max_payload_len) 249762306a36Sopenharmony_ci slot->base.data = pool->payload_buf + 249862306a36Sopenharmony_ci (i * req->max_payload_len); 249962306a36Sopenharmony_ci 250062306a36Sopenharmony_ci list_add_tail(&slot->node, &pool->free_slots); 250162306a36Sopenharmony_ci pool->num_slots++; 250262306a36Sopenharmony_ci } 250362306a36Sopenharmony_ci 250462306a36Sopenharmony_ci return pool; 250562306a36Sopenharmony_ci 250662306a36Sopenharmony_cierr_free_pool: 250762306a36Sopenharmony_ci i3c_generic_ibi_free_pool(pool); 250862306a36Sopenharmony_ci return ERR_PTR(ret); 250962306a36Sopenharmony_ci} 251062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(i3c_generic_ibi_alloc_pool); 251162306a36Sopenharmony_ci 251262306a36Sopenharmony_ci/** 251362306a36Sopenharmony_ci * i3c_generic_ibi_get_free_slot() - Get a free slot from a generic IBI pool 251462306a36Sopenharmony_ci * @pool: the pool to query an IBI slot on 251562306a36Sopenharmony_ci * 251662306a36Sopenharmony_ci * Search for a free slot in a generic IBI pool. 251762306a36Sopenharmony_ci * The slot should be returned to the pool using i3c_generic_ibi_recycle_slot() 251862306a36Sopenharmony_ci * when it's no longer needed. 251962306a36Sopenharmony_ci * 252062306a36Sopenharmony_ci * Return: a pointer to a free slot, or NULL if there's no free slot available. 252162306a36Sopenharmony_ci */ 252262306a36Sopenharmony_cistruct i3c_ibi_slot * 252362306a36Sopenharmony_cii3c_generic_ibi_get_free_slot(struct i3c_generic_ibi_pool *pool) 252462306a36Sopenharmony_ci{ 252562306a36Sopenharmony_ci struct i3c_generic_ibi_slot *slot; 252662306a36Sopenharmony_ci unsigned long flags; 252762306a36Sopenharmony_ci 252862306a36Sopenharmony_ci spin_lock_irqsave(&pool->lock, flags); 252962306a36Sopenharmony_ci slot = list_first_entry_or_null(&pool->free_slots, 253062306a36Sopenharmony_ci struct i3c_generic_ibi_slot, node); 253162306a36Sopenharmony_ci if (slot) 253262306a36Sopenharmony_ci list_del(&slot->node); 253362306a36Sopenharmony_ci spin_unlock_irqrestore(&pool->lock, flags); 253462306a36Sopenharmony_ci 253562306a36Sopenharmony_ci return slot ? &slot->base : NULL; 253662306a36Sopenharmony_ci} 253762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(i3c_generic_ibi_get_free_slot); 253862306a36Sopenharmony_ci 253962306a36Sopenharmony_ci/** 254062306a36Sopenharmony_ci * i3c_generic_ibi_recycle_slot() - Return a slot to a generic IBI pool 254162306a36Sopenharmony_ci * @pool: the pool to return the IBI slot to 254262306a36Sopenharmony_ci * @s: IBI slot to recycle 254362306a36Sopenharmony_ci * 254462306a36Sopenharmony_ci * Add an IBI slot back to its generic IBI pool. Should be called from the 254562306a36Sopenharmony_ci * master driver struct_master_controller_ops->recycle_ibi() method. 254662306a36Sopenharmony_ci */ 254762306a36Sopenharmony_civoid i3c_generic_ibi_recycle_slot(struct i3c_generic_ibi_pool *pool, 254862306a36Sopenharmony_ci struct i3c_ibi_slot *s) 254962306a36Sopenharmony_ci{ 255062306a36Sopenharmony_ci struct i3c_generic_ibi_slot *slot; 255162306a36Sopenharmony_ci unsigned long flags; 255262306a36Sopenharmony_ci 255362306a36Sopenharmony_ci if (!s) 255462306a36Sopenharmony_ci return; 255562306a36Sopenharmony_ci 255662306a36Sopenharmony_ci slot = container_of(s, struct i3c_generic_ibi_slot, base); 255762306a36Sopenharmony_ci spin_lock_irqsave(&pool->lock, flags); 255862306a36Sopenharmony_ci list_add_tail(&slot->node, &pool->free_slots); 255962306a36Sopenharmony_ci spin_unlock_irqrestore(&pool->lock, flags); 256062306a36Sopenharmony_ci} 256162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(i3c_generic_ibi_recycle_slot); 256262306a36Sopenharmony_ci 256362306a36Sopenharmony_cistatic int i3c_master_check_ops(const struct i3c_master_controller_ops *ops) 256462306a36Sopenharmony_ci{ 256562306a36Sopenharmony_ci if (!ops || !ops->bus_init || !ops->priv_xfers || 256662306a36Sopenharmony_ci !ops->send_ccc_cmd || !ops->do_daa || !ops->i2c_xfers) 256762306a36Sopenharmony_ci return -EINVAL; 256862306a36Sopenharmony_ci 256962306a36Sopenharmony_ci if (ops->request_ibi && 257062306a36Sopenharmony_ci (!ops->enable_ibi || !ops->disable_ibi || !ops->free_ibi || 257162306a36Sopenharmony_ci !ops->recycle_ibi_slot)) 257262306a36Sopenharmony_ci return -EINVAL; 257362306a36Sopenharmony_ci 257462306a36Sopenharmony_ci return 0; 257562306a36Sopenharmony_ci} 257662306a36Sopenharmony_ci 257762306a36Sopenharmony_ci/** 257862306a36Sopenharmony_ci * i3c_master_register() - register an I3C master 257962306a36Sopenharmony_ci * @master: master used to send frames on the bus 258062306a36Sopenharmony_ci * @parent: the parent device (the one that provides this I3C master 258162306a36Sopenharmony_ci * controller) 258262306a36Sopenharmony_ci * @ops: the master controller operations 258362306a36Sopenharmony_ci * @secondary: true if you are registering a secondary master. Will return 258462306a36Sopenharmony_ci * -ENOTSUPP if set to true since secondary masters are not yet 258562306a36Sopenharmony_ci * supported 258662306a36Sopenharmony_ci * 258762306a36Sopenharmony_ci * This function takes care of everything for you: 258862306a36Sopenharmony_ci * 258962306a36Sopenharmony_ci * - creates and initializes the I3C bus 259062306a36Sopenharmony_ci * - populates the bus with static I2C devs if @parent->of_node is not 259162306a36Sopenharmony_ci * NULL 259262306a36Sopenharmony_ci * - registers all I3C devices added by the controller during bus 259362306a36Sopenharmony_ci * initialization 259462306a36Sopenharmony_ci * - registers the I2C adapter and all I2C devices 259562306a36Sopenharmony_ci * 259662306a36Sopenharmony_ci * Return: 0 in case of success, a negative error code otherwise. 259762306a36Sopenharmony_ci */ 259862306a36Sopenharmony_ciint i3c_master_register(struct i3c_master_controller *master, 259962306a36Sopenharmony_ci struct device *parent, 260062306a36Sopenharmony_ci const struct i3c_master_controller_ops *ops, 260162306a36Sopenharmony_ci bool secondary) 260262306a36Sopenharmony_ci{ 260362306a36Sopenharmony_ci unsigned long i2c_scl_rate = I3C_BUS_I2C_FM_PLUS_SCL_RATE; 260462306a36Sopenharmony_ci struct i3c_bus *i3cbus = i3c_master_get_bus(master); 260562306a36Sopenharmony_ci enum i3c_bus_mode mode = I3C_BUS_MODE_PURE; 260662306a36Sopenharmony_ci struct i2c_dev_boardinfo *i2cbi; 260762306a36Sopenharmony_ci int ret; 260862306a36Sopenharmony_ci 260962306a36Sopenharmony_ci /* We do not support secondary masters yet. */ 261062306a36Sopenharmony_ci if (secondary) 261162306a36Sopenharmony_ci return -ENOTSUPP; 261262306a36Sopenharmony_ci 261362306a36Sopenharmony_ci ret = i3c_master_check_ops(ops); 261462306a36Sopenharmony_ci if (ret) 261562306a36Sopenharmony_ci return ret; 261662306a36Sopenharmony_ci 261762306a36Sopenharmony_ci master->dev.parent = parent; 261862306a36Sopenharmony_ci master->dev.of_node = of_node_get(parent->of_node); 261962306a36Sopenharmony_ci master->dev.bus = &i3c_bus_type; 262062306a36Sopenharmony_ci master->dev.type = &i3c_masterdev_type; 262162306a36Sopenharmony_ci master->dev.release = i3c_masterdev_release; 262262306a36Sopenharmony_ci master->ops = ops; 262362306a36Sopenharmony_ci master->secondary = secondary; 262462306a36Sopenharmony_ci INIT_LIST_HEAD(&master->boardinfo.i2c); 262562306a36Sopenharmony_ci INIT_LIST_HEAD(&master->boardinfo.i3c); 262662306a36Sopenharmony_ci 262762306a36Sopenharmony_ci ret = i3c_bus_init(i3cbus, master->dev.of_node); 262862306a36Sopenharmony_ci if (ret) 262962306a36Sopenharmony_ci return ret; 263062306a36Sopenharmony_ci 263162306a36Sopenharmony_ci device_initialize(&master->dev); 263262306a36Sopenharmony_ci dev_set_name(&master->dev, "i3c-%d", i3cbus->id); 263362306a36Sopenharmony_ci 263462306a36Sopenharmony_ci ret = of_populate_i3c_bus(master); 263562306a36Sopenharmony_ci if (ret) 263662306a36Sopenharmony_ci goto err_put_dev; 263762306a36Sopenharmony_ci 263862306a36Sopenharmony_ci list_for_each_entry(i2cbi, &master->boardinfo.i2c, node) { 263962306a36Sopenharmony_ci switch (i2cbi->lvr & I3C_LVR_I2C_INDEX_MASK) { 264062306a36Sopenharmony_ci case I3C_LVR_I2C_INDEX(0): 264162306a36Sopenharmony_ci if (mode < I3C_BUS_MODE_MIXED_FAST) 264262306a36Sopenharmony_ci mode = I3C_BUS_MODE_MIXED_FAST; 264362306a36Sopenharmony_ci break; 264462306a36Sopenharmony_ci case I3C_LVR_I2C_INDEX(1): 264562306a36Sopenharmony_ci if (mode < I3C_BUS_MODE_MIXED_LIMITED) 264662306a36Sopenharmony_ci mode = I3C_BUS_MODE_MIXED_LIMITED; 264762306a36Sopenharmony_ci break; 264862306a36Sopenharmony_ci case I3C_LVR_I2C_INDEX(2): 264962306a36Sopenharmony_ci if (mode < I3C_BUS_MODE_MIXED_SLOW) 265062306a36Sopenharmony_ci mode = I3C_BUS_MODE_MIXED_SLOW; 265162306a36Sopenharmony_ci break; 265262306a36Sopenharmony_ci default: 265362306a36Sopenharmony_ci ret = -EINVAL; 265462306a36Sopenharmony_ci goto err_put_dev; 265562306a36Sopenharmony_ci } 265662306a36Sopenharmony_ci 265762306a36Sopenharmony_ci if (i2cbi->lvr & I3C_LVR_I2C_FM_MODE) 265862306a36Sopenharmony_ci i2c_scl_rate = I3C_BUS_I2C_FM_SCL_RATE; 265962306a36Sopenharmony_ci } 266062306a36Sopenharmony_ci 266162306a36Sopenharmony_ci ret = i3c_bus_set_mode(i3cbus, mode, i2c_scl_rate); 266262306a36Sopenharmony_ci if (ret) 266362306a36Sopenharmony_ci goto err_put_dev; 266462306a36Sopenharmony_ci 266562306a36Sopenharmony_ci master->wq = alloc_workqueue("%s", 0, 0, dev_name(parent)); 266662306a36Sopenharmony_ci if (!master->wq) { 266762306a36Sopenharmony_ci ret = -ENOMEM; 266862306a36Sopenharmony_ci goto err_put_dev; 266962306a36Sopenharmony_ci } 267062306a36Sopenharmony_ci 267162306a36Sopenharmony_ci ret = i3c_master_bus_init(master); 267262306a36Sopenharmony_ci if (ret) 267362306a36Sopenharmony_ci goto err_put_dev; 267462306a36Sopenharmony_ci 267562306a36Sopenharmony_ci ret = device_add(&master->dev); 267662306a36Sopenharmony_ci if (ret) 267762306a36Sopenharmony_ci goto err_cleanup_bus; 267862306a36Sopenharmony_ci 267962306a36Sopenharmony_ci /* 268062306a36Sopenharmony_ci * Expose our I3C bus as an I2C adapter so that I2C devices are exposed 268162306a36Sopenharmony_ci * through the I2C subsystem. 268262306a36Sopenharmony_ci */ 268362306a36Sopenharmony_ci ret = i3c_master_i2c_adapter_init(master); 268462306a36Sopenharmony_ci if (ret) 268562306a36Sopenharmony_ci goto err_del_dev; 268662306a36Sopenharmony_ci 268762306a36Sopenharmony_ci /* 268862306a36Sopenharmony_ci * We're done initializing the bus and the controller, we can now 268962306a36Sopenharmony_ci * register I3C devices discovered during the initial DAA. 269062306a36Sopenharmony_ci */ 269162306a36Sopenharmony_ci master->init_done = true; 269262306a36Sopenharmony_ci i3c_bus_normaluse_lock(&master->bus); 269362306a36Sopenharmony_ci i3c_master_register_new_i3c_devs(master); 269462306a36Sopenharmony_ci i3c_bus_normaluse_unlock(&master->bus); 269562306a36Sopenharmony_ci 269662306a36Sopenharmony_ci return 0; 269762306a36Sopenharmony_ci 269862306a36Sopenharmony_cierr_del_dev: 269962306a36Sopenharmony_ci device_del(&master->dev); 270062306a36Sopenharmony_ci 270162306a36Sopenharmony_cierr_cleanup_bus: 270262306a36Sopenharmony_ci i3c_master_bus_cleanup(master); 270362306a36Sopenharmony_ci 270462306a36Sopenharmony_cierr_put_dev: 270562306a36Sopenharmony_ci put_device(&master->dev); 270662306a36Sopenharmony_ci 270762306a36Sopenharmony_ci return ret; 270862306a36Sopenharmony_ci} 270962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(i3c_master_register); 271062306a36Sopenharmony_ci 271162306a36Sopenharmony_ci/** 271262306a36Sopenharmony_ci * i3c_master_unregister() - unregister an I3C master 271362306a36Sopenharmony_ci * @master: master used to send frames on the bus 271462306a36Sopenharmony_ci * 271562306a36Sopenharmony_ci * Basically undo everything done in i3c_master_register(). 271662306a36Sopenharmony_ci */ 271762306a36Sopenharmony_civoid i3c_master_unregister(struct i3c_master_controller *master) 271862306a36Sopenharmony_ci{ 271962306a36Sopenharmony_ci i3c_master_i2c_adapter_cleanup(master); 272062306a36Sopenharmony_ci i3c_master_unregister_i3c_devs(master); 272162306a36Sopenharmony_ci i3c_master_bus_cleanup(master); 272262306a36Sopenharmony_ci device_unregister(&master->dev); 272362306a36Sopenharmony_ci} 272462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(i3c_master_unregister); 272562306a36Sopenharmony_ci 272662306a36Sopenharmony_ciint i3c_dev_setdasa_locked(struct i3c_dev_desc *dev) 272762306a36Sopenharmony_ci{ 272862306a36Sopenharmony_ci struct i3c_master_controller *master; 272962306a36Sopenharmony_ci 273062306a36Sopenharmony_ci if (!dev) 273162306a36Sopenharmony_ci return -ENOENT; 273262306a36Sopenharmony_ci 273362306a36Sopenharmony_ci master = i3c_dev_get_master(dev); 273462306a36Sopenharmony_ci if (!master) 273562306a36Sopenharmony_ci return -EINVAL; 273662306a36Sopenharmony_ci 273762306a36Sopenharmony_ci if (!dev->boardinfo || !dev->boardinfo->init_dyn_addr || 273862306a36Sopenharmony_ci !dev->boardinfo->static_addr) 273962306a36Sopenharmony_ci return -EINVAL; 274062306a36Sopenharmony_ci 274162306a36Sopenharmony_ci return i3c_master_setdasa_locked(master, dev->info.static_addr, 274262306a36Sopenharmony_ci dev->boardinfo->init_dyn_addr); 274362306a36Sopenharmony_ci} 274462306a36Sopenharmony_ci 274562306a36Sopenharmony_ciint i3c_dev_do_priv_xfers_locked(struct i3c_dev_desc *dev, 274662306a36Sopenharmony_ci struct i3c_priv_xfer *xfers, 274762306a36Sopenharmony_ci int nxfers) 274862306a36Sopenharmony_ci{ 274962306a36Sopenharmony_ci struct i3c_master_controller *master; 275062306a36Sopenharmony_ci 275162306a36Sopenharmony_ci if (!dev) 275262306a36Sopenharmony_ci return -ENOENT; 275362306a36Sopenharmony_ci 275462306a36Sopenharmony_ci master = i3c_dev_get_master(dev); 275562306a36Sopenharmony_ci if (!master || !xfers) 275662306a36Sopenharmony_ci return -EINVAL; 275762306a36Sopenharmony_ci 275862306a36Sopenharmony_ci if (!master->ops->priv_xfers) 275962306a36Sopenharmony_ci return -ENOTSUPP; 276062306a36Sopenharmony_ci 276162306a36Sopenharmony_ci return master->ops->priv_xfers(dev, xfers, nxfers); 276262306a36Sopenharmony_ci} 276362306a36Sopenharmony_ci 276462306a36Sopenharmony_ciint i3c_dev_disable_ibi_locked(struct i3c_dev_desc *dev) 276562306a36Sopenharmony_ci{ 276662306a36Sopenharmony_ci struct i3c_master_controller *master; 276762306a36Sopenharmony_ci int ret; 276862306a36Sopenharmony_ci 276962306a36Sopenharmony_ci if (!dev->ibi) 277062306a36Sopenharmony_ci return -EINVAL; 277162306a36Sopenharmony_ci 277262306a36Sopenharmony_ci master = i3c_dev_get_master(dev); 277362306a36Sopenharmony_ci ret = master->ops->disable_ibi(dev); 277462306a36Sopenharmony_ci if (ret) 277562306a36Sopenharmony_ci return ret; 277662306a36Sopenharmony_ci 277762306a36Sopenharmony_ci reinit_completion(&dev->ibi->all_ibis_handled); 277862306a36Sopenharmony_ci if (atomic_read(&dev->ibi->pending_ibis)) 277962306a36Sopenharmony_ci wait_for_completion(&dev->ibi->all_ibis_handled); 278062306a36Sopenharmony_ci 278162306a36Sopenharmony_ci dev->ibi->enabled = false; 278262306a36Sopenharmony_ci 278362306a36Sopenharmony_ci return 0; 278462306a36Sopenharmony_ci} 278562306a36Sopenharmony_ci 278662306a36Sopenharmony_ciint i3c_dev_enable_ibi_locked(struct i3c_dev_desc *dev) 278762306a36Sopenharmony_ci{ 278862306a36Sopenharmony_ci struct i3c_master_controller *master = i3c_dev_get_master(dev); 278962306a36Sopenharmony_ci int ret; 279062306a36Sopenharmony_ci 279162306a36Sopenharmony_ci if (!dev->ibi) 279262306a36Sopenharmony_ci return -EINVAL; 279362306a36Sopenharmony_ci 279462306a36Sopenharmony_ci ret = master->ops->enable_ibi(dev); 279562306a36Sopenharmony_ci if (!ret) 279662306a36Sopenharmony_ci dev->ibi->enabled = true; 279762306a36Sopenharmony_ci 279862306a36Sopenharmony_ci return ret; 279962306a36Sopenharmony_ci} 280062306a36Sopenharmony_ci 280162306a36Sopenharmony_ciint i3c_dev_request_ibi_locked(struct i3c_dev_desc *dev, 280262306a36Sopenharmony_ci const struct i3c_ibi_setup *req) 280362306a36Sopenharmony_ci{ 280462306a36Sopenharmony_ci struct i3c_master_controller *master = i3c_dev_get_master(dev); 280562306a36Sopenharmony_ci struct i3c_device_ibi_info *ibi; 280662306a36Sopenharmony_ci int ret; 280762306a36Sopenharmony_ci 280862306a36Sopenharmony_ci if (!master->ops->request_ibi) 280962306a36Sopenharmony_ci return -ENOTSUPP; 281062306a36Sopenharmony_ci 281162306a36Sopenharmony_ci if (dev->ibi) 281262306a36Sopenharmony_ci return -EBUSY; 281362306a36Sopenharmony_ci 281462306a36Sopenharmony_ci ibi = kzalloc(sizeof(*ibi), GFP_KERNEL); 281562306a36Sopenharmony_ci if (!ibi) 281662306a36Sopenharmony_ci return -ENOMEM; 281762306a36Sopenharmony_ci 281862306a36Sopenharmony_ci atomic_set(&ibi->pending_ibis, 0); 281962306a36Sopenharmony_ci init_completion(&ibi->all_ibis_handled); 282062306a36Sopenharmony_ci ibi->handler = req->handler; 282162306a36Sopenharmony_ci ibi->max_payload_len = req->max_payload_len; 282262306a36Sopenharmony_ci ibi->num_slots = req->num_slots; 282362306a36Sopenharmony_ci 282462306a36Sopenharmony_ci dev->ibi = ibi; 282562306a36Sopenharmony_ci ret = master->ops->request_ibi(dev, req); 282662306a36Sopenharmony_ci if (ret) { 282762306a36Sopenharmony_ci kfree(ibi); 282862306a36Sopenharmony_ci dev->ibi = NULL; 282962306a36Sopenharmony_ci } 283062306a36Sopenharmony_ci 283162306a36Sopenharmony_ci return ret; 283262306a36Sopenharmony_ci} 283362306a36Sopenharmony_ci 283462306a36Sopenharmony_civoid i3c_dev_free_ibi_locked(struct i3c_dev_desc *dev) 283562306a36Sopenharmony_ci{ 283662306a36Sopenharmony_ci struct i3c_master_controller *master = i3c_dev_get_master(dev); 283762306a36Sopenharmony_ci 283862306a36Sopenharmony_ci if (!dev->ibi) 283962306a36Sopenharmony_ci return; 284062306a36Sopenharmony_ci 284162306a36Sopenharmony_ci if (WARN_ON(dev->ibi->enabled)) 284262306a36Sopenharmony_ci WARN_ON(i3c_dev_disable_ibi_locked(dev)); 284362306a36Sopenharmony_ci 284462306a36Sopenharmony_ci master->ops->free_ibi(dev); 284562306a36Sopenharmony_ci kfree(dev->ibi); 284662306a36Sopenharmony_ci dev->ibi = NULL; 284762306a36Sopenharmony_ci} 284862306a36Sopenharmony_ci 284962306a36Sopenharmony_cistatic int __init i3c_init(void) 285062306a36Sopenharmony_ci{ 285162306a36Sopenharmony_ci int res; 285262306a36Sopenharmony_ci 285362306a36Sopenharmony_ci res = of_alias_get_highest_id("i3c"); 285462306a36Sopenharmony_ci if (res >= 0) { 285562306a36Sopenharmony_ci mutex_lock(&i3c_core_lock); 285662306a36Sopenharmony_ci __i3c_first_dynamic_bus_num = res + 1; 285762306a36Sopenharmony_ci mutex_unlock(&i3c_core_lock); 285862306a36Sopenharmony_ci } 285962306a36Sopenharmony_ci 286062306a36Sopenharmony_ci res = bus_register_notifier(&i2c_bus_type, &i2cdev_notifier); 286162306a36Sopenharmony_ci if (res) 286262306a36Sopenharmony_ci return res; 286362306a36Sopenharmony_ci 286462306a36Sopenharmony_ci res = bus_register(&i3c_bus_type); 286562306a36Sopenharmony_ci if (res) 286662306a36Sopenharmony_ci goto out_unreg_notifier; 286762306a36Sopenharmony_ci 286862306a36Sopenharmony_ci return 0; 286962306a36Sopenharmony_ci 287062306a36Sopenharmony_ciout_unreg_notifier: 287162306a36Sopenharmony_ci bus_unregister_notifier(&i2c_bus_type, &i2cdev_notifier); 287262306a36Sopenharmony_ci 287362306a36Sopenharmony_ci return res; 287462306a36Sopenharmony_ci} 287562306a36Sopenharmony_cisubsys_initcall(i3c_init); 287662306a36Sopenharmony_ci 287762306a36Sopenharmony_cistatic void __exit i3c_exit(void) 287862306a36Sopenharmony_ci{ 287962306a36Sopenharmony_ci bus_unregister_notifier(&i2c_bus_type, &i2cdev_notifier); 288062306a36Sopenharmony_ci idr_destroy(&i3c_bus_idr); 288162306a36Sopenharmony_ci bus_unregister(&i3c_bus_type); 288262306a36Sopenharmony_ci} 288362306a36Sopenharmony_cimodule_exit(i3c_exit); 288462306a36Sopenharmony_ci 288562306a36Sopenharmony_ciMODULE_AUTHOR("Boris Brezillon <boris.brezillon@bootlin.com>"); 288662306a36Sopenharmony_ciMODULE_DESCRIPTION("I3C core"); 288762306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 2888