root/drivers/usb/typec/mux/pi3usb30532.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. pi3usb30532_set_conf
  2. pi3usb30532_sw_set
  3. pi3usb30532_mux_set
  4. pi3usb30532_probe
  5. pi3usb30532_remove

   1 // SPDX-License-Identifier: GPL-2.0+
   2 /*
   3  * Pericom PI3USB30532 Type-C cross switch / mux driver
   4  *
   5  * Copyright (c) 2017-2018 Hans de Goede <hdegoede@redhat.com>
   6  */
   7 
   8 #include <linux/i2c.h>
   9 #include <linux/kernel.h>
  10 #include <linux/module.h>
  11 #include <linux/mutex.h>
  12 #include <linux/usb/typec_dp.h>
  13 #include <linux/usb/typec_mux.h>
  14 
  15 #define PI3USB30532_CONF                        0x00
  16 
  17 #define PI3USB30532_CONF_OPEN                   0x00
  18 #define PI3USB30532_CONF_SWAP                   0x01
  19 #define PI3USB30532_CONF_4LANE_DP               0x02
  20 #define PI3USB30532_CONF_USB3                   0x04
  21 #define PI3USB30532_CONF_USB3_AND_2LANE_DP      0x06
  22 
  23 struct pi3usb30532 {
  24         struct i2c_client *client;
  25         struct mutex lock; /* protects the cached conf register */
  26         struct typec_switch *sw;
  27         struct typec_mux *mux;
  28         u8 conf;
  29 };
  30 
  31 static int pi3usb30532_set_conf(struct pi3usb30532 *pi, u8 new_conf)
  32 {
  33         int ret = 0;
  34 
  35         if (pi->conf == new_conf)
  36                 return 0;
  37 
  38         ret = i2c_smbus_write_byte_data(pi->client, PI3USB30532_CONF, new_conf);
  39         if (ret) {
  40                 dev_err(&pi->client->dev, "Error writing conf: %d\n", ret);
  41                 return ret;
  42         }
  43 
  44         pi->conf = new_conf;
  45         return 0;
  46 }
  47 
  48 static int pi3usb30532_sw_set(struct typec_switch *sw,
  49                               enum typec_orientation orientation)
  50 {
  51         struct pi3usb30532 *pi = typec_switch_get_drvdata(sw);
  52         u8 new_conf;
  53         int ret;
  54 
  55         mutex_lock(&pi->lock);
  56         new_conf = pi->conf;
  57 
  58         switch (orientation) {
  59         case TYPEC_ORIENTATION_NONE:
  60                 new_conf = PI3USB30532_CONF_OPEN;
  61                 break;
  62         case TYPEC_ORIENTATION_NORMAL:
  63                 new_conf &= ~PI3USB30532_CONF_SWAP;
  64                 break;
  65         case TYPEC_ORIENTATION_REVERSE:
  66                 new_conf |= PI3USB30532_CONF_SWAP;
  67                 break;
  68         }
  69 
  70         ret = pi3usb30532_set_conf(pi, new_conf);
  71         mutex_unlock(&pi->lock);
  72 
  73         return ret;
  74 }
  75 
  76 static int pi3usb30532_mux_set(struct typec_mux *mux, int state)
  77 {
  78         struct pi3usb30532 *pi = typec_mux_get_drvdata(mux);
  79         u8 new_conf;
  80         int ret;
  81 
  82         mutex_lock(&pi->lock);
  83         new_conf = pi->conf;
  84 
  85         switch (state) {
  86         case TYPEC_STATE_SAFE:
  87                 new_conf = (new_conf & PI3USB30532_CONF_SWAP) |
  88                            PI3USB30532_CONF_OPEN;
  89                 break;
  90         case TYPEC_STATE_USB:
  91                 new_conf = (new_conf & PI3USB30532_CONF_SWAP) |
  92                            PI3USB30532_CONF_USB3;
  93                 break;
  94         case TYPEC_DP_STATE_C:
  95         case TYPEC_DP_STATE_E:
  96                 new_conf = (new_conf & PI3USB30532_CONF_SWAP) |
  97                            PI3USB30532_CONF_4LANE_DP;
  98                 break;
  99         case TYPEC_DP_STATE_D:
 100                 new_conf = (new_conf & PI3USB30532_CONF_SWAP) |
 101                            PI3USB30532_CONF_USB3_AND_2LANE_DP;
 102                 break;
 103         default:
 104                 break;
 105         }
 106 
 107         ret = pi3usb30532_set_conf(pi, new_conf);
 108         mutex_unlock(&pi->lock);
 109 
 110         return ret;
 111 }
 112 
 113 static int pi3usb30532_probe(struct i2c_client *client)
 114 {
 115         struct device *dev = &client->dev;
 116         struct typec_switch_desc sw_desc;
 117         struct typec_mux_desc mux_desc;
 118         struct pi3usb30532 *pi;
 119         int ret;
 120 
 121         pi = devm_kzalloc(dev, sizeof(*pi), GFP_KERNEL);
 122         if (!pi)
 123                 return -ENOMEM;
 124 
 125         pi->client = client;
 126         mutex_init(&pi->lock);
 127 
 128         ret = i2c_smbus_read_byte_data(client, PI3USB30532_CONF);
 129         if (ret < 0) {
 130                 dev_err(dev, "Error reading config register %d\n", ret);
 131                 return ret;
 132         }
 133         pi->conf = ret;
 134 
 135         sw_desc.drvdata = pi;
 136         sw_desc.fwnode = dev->fwnode;
 137         sw_desc.set = pi3usb30532_sw_set;
 138 
 139         pi->sw = typec_switch_register(dev, &sw_desc);
 140         if (IS_ERR(pi->sw)) {
 141                 dev_err(dev, "Error registering typec switch: %ld\n",
 142                         PTR_ERR(pi->sw));
 143                 return PTR_ERR(pi->sw);
 144         }
 145 
 146         mux_desc.drvdata = pi;
 147         mux_desc.fwnode = dev->fwnode;
 148         mux_desc.set = pi3usb30532_mux_set;
 149 
 150         pi->mux = typec_mux_register(dev, &mux_desc);
 151         if (IS_ERR(pi->mux)) {
 152                 typec_switch_unregister(pi->sw);
 153                 dev_err(dev, "Error registering typec mux: %ld\n",
 154                         PTR_ERR(pi->mux));
 155                 return PTR_ERR(pi->mux);
 156         }
 157 
 158         i2c_set_clientdata(client, pi);
 159         return 0;
 160 }
 161 
 162 static int pi3usb30532_remove(struct i2c_client *client)
 163 {
 164         struct pi3usb30532 *pi = i2c_get_clientdata(client);
 165 
 166         typec_mux_unregister(pi->mux);
 167         typec_switch_unregister(pi->sw);
 168         return 0;
 169 }
 170 
 171 static const struct i2c_device_id pi3usb30532_table[] = {
 172         { "pi3usb30532" },
 173         { }
 174 };
 175 MODULE_DEVICE_TABLE(i2c, pi3usb30532_table);
 176 
 177 static struct i2c_driver pi3usb30532_driver = {
 178         .driver = {
 179                 .name = "pi3usb30532",
 180         },
 181         .probe_new      = pi3usb30532_probe,
 182         .remove         = pi3usb30532_remove,
 183         .id_table       = pi3usb30532_table,
 184 };
 185 
 186 module_i2c_driver(pi3usb30532_driver);
 187 
 188 MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
 189 MODULE_DESCRIPTION("Pericom PI3USB30532 Type-C mux driver");
 190 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */