i3c: master: Use struct_size() helper
[sfrench/cifs-2.6.git] / drivers / i3c / master.c
index 1412abcff01095cd001ece69bb80a69d714a80ba..d6f8b038a89678fcd40bce106e020c902aa4cbd3 100644 (file)
@@ -91,6 +91,12 @@ void i3c_bus_normaluse_unlock(struct i3c_bus *bus)
        up_read(&bus->lock);
 }
 
+static struct i3c_master_controller *
+i3c_bus_to_i3c_master(struct i3c_bus *i3cbus)
+{
+       return container_of(i3cbus, struct i3c_master_controller, bus);
+}
+
 static struct i3c_master_controller *dev_to_i3cmaster(struct device *dev)
 {
        return container_of(dev, struct i3c_master_controller, dev);
@@ -385,8 +391,9 @@ static void i3c_bus_set_addr_slot_status(struct i3c_bus *bus, u16 addr,
                return;
 
        ptr = bus->addrslots + (bitpos / BITS_PER_LONG);
-       *ptr &= ~(I3C_ADDR_SLOT_STATUS_MASK << (bitpos % BITS_PER_LONG));
-       *ptr |= status << (bitpos % BITS_PER_LONG);
+       *ptr &= ~((unsigned long)I3C_ADDR_SLOT_STATUS_MASK <<
+                                               (bitpos % BITS_PER_LONG));
+       *ptr |= (unsigned long)status << (bitpos % BITS_PER_LONG);
 }
 
 static bool i3c_bus_dev_addr_is_avail(struct i3c_bus *bus, u8 addr)
@@ -463,6 +470,7 @@ static int i3c_bus_init(struct i3c_bus *i3cbus)
 static const char * const i3c_bus_mode_strings[] = {
        [I3C_BUS_MODE_PURE] = "pure",
        [I3C_BUS_MODE_MIXED_FAST] = "mixed-fast",
+       [I3C_BUS_MODE_MIXED_LIMITED] = "mixed-limited",
        [I3C_BUS_MODE_MIXED_SLOW] = "mixed-slow",
 };
 
@@ -564,20 +572,39 @@ static const struct device_type i3c_masterdev_type = {
        .groups = i3c_masterdev_groups,
 };
 
-int i3c_bus_set_mode(struct i3c_bus *i3cbus, enum i3c_bus_mode mode)
+int i3c_bus_set_mode(struct i3c_bus *i3cbus, enum i3c_bus_mode mode,
+                    unsigned long max_i2c_scl_rate)
 {
-       i3cbus->mode = mode;
+       struct i3c_master_controller *master = i3c_bus_to_i3c_master(i3cbus);
 
-       if (!i3cbus->scl_rate.i3c)
-               i3cbus->scl_rate.i3c = I3C_BUS_TYP_I3C_SCL_RATE;
+       i3cbus->mode = mode;
 
-       if (!i3cbus->scl_rate.i2c) {
-               if (i3cbus->mode == I3C_BUS_MODE_MIXED_SLOW)
-                       i3cbus->scl_rate.i2c = I3C_BUS_I2C_FM_SCL_RATE;
-               else
-                       i3cbus->scl_rate.i2c = I3C_BUS_I2C_FM_PLUS_SCL_RATE;
+       switch (i3cbus->mode) {
+       case I3C_BUS_MODE_PURE:
+               if (!i3cbus->scl_rate.i3c)
+                       i3cbus->scl_rate.i3c = I3C_BUS_TYP_I3C_SCL_RATE;
+               break;
+       case I3C_BUS_MODE_MIXED_FAST:
+       case I3C_BUS_MODE_MIXED_LIMITED:
+               if (!i3cbus->scl_rate.i3c)
+                       i3cbus->scl_rate.i3c = I3C_BUS_TYP_I3C_SCL_RATE;
+               if (!i3cbus->scl_rate.i2c)
+                       i3cbus->scl_rate.i2c = max_i2c_scl_rate;
+               break;
+       case I3C_BUS_MODE_MIXED_SLOW:
+               if (!i3cbus->scl_rate.i2c)
+                       i3cbus->scl_rate.i2c = max_i2c_scl_rate;
+               if (!i3cbus->scl_rate.i3c ||
+                   i3cbus->scl_rate.i3c > i3cbus->scl_rate.i2c)
+                       i3cbus->scl_rate.i3c = i3cbus->scl_rate.i2c;
+               break;
+       default:
+               return -EINVAL;
        }
 
+       dev_dbg(&master->dev, "i2c-scl = %ld Hz i3c-scl = %ld Hz\n",
+               i3cbus->scl_rate.i2c, i3cbus->scl_rate.i3c);
+
        /*
         * I3C/I2C frequency may have been overridden, check that user-provided
         * values are not exceeding max possible frequency.
@@ -923,9 +950,8 @@ int i3c_master_defslvs_locked(struct i3c_master_controller *master)
                ndevs++;
 
        defslvs = i3c_ccc_cmd_dest_init(&dest, I3C_BROADCAST_ADDR,
-                                       sizeof(*defslvs) +
-                                       ((ndevs - 1) *
-                                        sizeof(struct i3c_ccc_dev_desc)));
+                                       struct_size(defslvs, slaves,
+                                                   ndevs - 1));
        if (!defslvs)
                return -ENOMEM;
 
@@ -1962,12 +1988,19 @@ of_i3c_master_add_i2c_boardinfo(struct i3c_master_controller *master,
        if (ret)
                return ret;
 
+       /*
+        * The I3C Specification does not clearly say I2C devices with 10-bit
+        * address are supported. These devices can't be passed properly through
+        * DEFSLVS command.
+        */
+       if (boardinfo->base.flags & I2C_CLIENT_TEN) {
+               dev_err(&master->dev, "I2C device with 10 bit address not supported.");
+               return -ENOTSUPP;
+       }
+
        /* LVR is encoded in reg[2]. */
        boardinfo->lvr = reg[2];
 
-       if (boardinfo->lvr & I3C_LVR_I2C_FM_MODE)
-               master->bus.scl_rate.i2c = I3C_BUS_I2C_FM_SCL_RATE;
-
        list_add_tail(&boardinfo->node, &master->boardinfo.i2c);
        of_node_get(node);
 
@@ -2110,16 +2143,14 @@ static int i3c_master_i2c_adapter_xfer(struct i2c_adapter *adap,
        return ret ? ret : nxfers;
 }
 
-static u32 i3c_master_i2c_functionalities(struct i2c_adapter *adap)
+static u32 i3c_master_i2c_funcs(struct i2c_adapter *adapter)
 {
-       struct i3c_master_controller *master = i2c_adapter_to_i3c_master(adap);
-
-       return master->ops->i2c_funcs(master);
+       return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C;
 }
 
 static const struct i2c_algorithm i3c_master_i2c_algo = {
        .master_xfer = i3c_master_i2c_adapter_xfer,
-       .functionality = i3c_master_i2c_functionalities,
+       .functionality = i3c_master_i2c_funcs,
 };
 
 static int i3c_master_i2c_adapter_init(struct i3c_master_controller *master)
@@ -2378,8 +2409,7 @@ EXPORT_SYMBOL_GPL(i3c_generic_ibi_recycle_slot);
 static int i3c_master_check_ops(const struct i3c_master_controller_ops *ops)
 {
        if (!ops || !ops->bus_init || !ops->priv_xfers ||
-           !ops->send_ccc_cmd || !ops->do_daa || !ops->i2c_xfers ||
-           !ops->i2c_funcs)
+           !ops->send_ccc_cmd || !ops->do_daa || !ops->i2c_xfers)
                return -EINVAL;
 
        if (ops->request_ibi &&
@@ -2416,6 +2446,7 @@ int i3c_master_register(struct i3c_master_controller *master,
                        const struct i3c_master_controller_ops *ops,
                        bool secondary)
 {
+       unsigned long i2c_scl_rate = I3C_BUS_I2C_FM_PLUS_SCL_RATE;
        struct i3c_bus *i3cbus = i3c_master_get_bus(master);
        enum i3c_bus_mode mode = I3C_BUS_MODE_PURE;
        struct i2c_dev_boardinfo *i2cbi;
@@ -2457,6 +2488,9 @@ int i3c_master_register(struct i3c_master_controller *master,
                                mode = I3C_BUS_MODE_MIXED_FAST;
                        break;
                case I3C_LVR_I2C_INDEX(1):
+                       if (mode < I3C_BUS_MODE_MIXED_LIMITED)
+                               mode = I3C_BUS_MODE_MIXED_LIMITED;
+                       break;
                case I3C_LVR_I2C_INDEX(2):
                        if (mode < I3C_BUS_MODE_MIXED_SLOW)
                                mode = I3C_BUS_MODE_MIXED_SLOW;
@@ -2465,9 +2499,12 @@ int i3c_master_register(struct i3c_master_controller *master,
                        ret = -EINVAL;
                        goto err_put_dev;
                }
+
+               if (i2cbi->lvr & I3C_LVR_I2C_FM_MODE)
+                       i2c_scl_rate = I3C_BUS_I2C_FM_SCL_RATE;
        }
 
-       ret = i3c_bus_set_mode(i3cbus, mode);
+       ret = i3c_bus_set_mode(i3cbus, mode, i2c_scl_rate);
        if (ret)
                goto err_put_dev;