The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/drm2/drm_dp_iic_helper.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Copyright © 2009 Keith Packard
    3  *
    4  * Permission to use, copy, modify, distribute, and sell this software and its
    5  * documentation for any purpose is hereby granted without fee, provided that
    6  * the above copyright notice appear in all copies and that both that copyright
    7  * notice and this permission notice appear in supporting documentation, and
    8  * that the name of the copyright holders not be used in advertising or
    9  * publicity pertaining to distribution of the software without specific,
   10  * written prior permission.  The copyright holders make no representations
   11  * about the suitability of this software for any purpose.  It is provided "as
   12  * is" without express or implied warranty.
   13  *
   14  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
   15  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
   16  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
   17  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
   18  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
   19  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
   20  * OF THIS SOFTWARE.
   21  */
   22 
   23 #include <sys/cdefs.h>
   24 __FBSDID("$FreeBSD$");
   25 
   26 #include <sys/types.h>
   27 #include <sys/kobj.h>
   28 #include <sys/bus.h>
   29 #include <dev/iicbus/iic.h>
   30 #include "iicbus_if.h"
   31 #include <dev/iicbus/iiconf.h>
   32 #include <dev/drm2/drmP.h>
   33 #include <dev/drm2/drm_dp_helper.h>
   34 
   35 static int
   36 iic_dp_aux_transaction(device_t idev, int mode, uint8_t write_byte,
   37     uint8_t *read_byte)
   38 {
   39         struct iic_dp_aux_data *aux_data;
   40         int ret;
   41 
   42         aux_data = device_get_softc(idev);
   43         ret = (*aux_data->aux_ch)(idev, mode, write_byte, read_byte);
   44         if (ret < 0)
   45                 return (ret);
   46         return (0);
   47 }
   48 
   49 /*
   50  * I2C over AUX CH
   51  */
   52 
   53 /*
   54  * Send the address. If the I2C link is running, this 'restarts'
   55  * the connection with the new address, this is used for doing
   56  * a write followed by a read (as needed for DDC)
   57  */
   58 static int
   59 iic_dp_aux_address(device_t idev, u16 address, bool reading)
   60 {
   61         struct iic_dp_aux_data *aux_data;
   62         int mode, ret;
   63 
   64         aux_data = device_get_softc(idev);
   65         mode = MODE_I2C_START;
   66         if (reading)
   67                 mode |= MODE_I2C_READ;
   68         else
   69                 mode |= MODE_I2C_WRITE;
   70         aux_data->address = address;
   71         aux_data->running = true;
   72         ret = iic_dp_aux_transaction(idev, mode, 0, NULL);
   73         return (ret);
   74 }
   75 
   76 /*
   77  * Stop the I2C transaction. This closes out the link, sending
   78  * a bare address packet with the MOT bit turned off
   79  */
   80 static void
   81 iic_dp_aux_stop(device_t idev, bool reading)
   82 {
   83         struct iic_dp_aux_data *aux_data;
   84         int mode;
   85 
   86         aux_data = device_get_softc(idev);
   87         mode = MODE_I2C_STOP;
   88         if (reading)
   89                 mode |= MODE_I2C_READ;
   90         else
   91                 mode |= MODE_I2C_WRITE;
   92         if (aux_data->running) {
   93                 (void)iic_dp_aux_transaction(idev, mode, 0, NULL);
   94                 aux_data->running = false;
   95         }
   96 }
   97 
   98 /*
   99  * Write a single byte to the current I2C address, the
  100  * the I2C link must be running or this returns -EIO
  101  */
  102 static int
  103 iic_dp_aux_put_byte(device_t idev, u8 byte)
  104 {
  105         struct iic_dp_aux_data *aux_data;
  106         int ret;
  107 
  108         aux_data = device_get_softc(idev);
  109 
  110         if (!aux_data->running)
  111                 return (-EIO);
  112 
  113         ret = iic_dp_aux_transaction(idev, MODE_I2C_WRITE, byte, NULL);
  114         return (ret);
  115 }
  116 
  117 /*
  118  * Read a single byte from the current I2C address, the
  119  * I2C link must be running or this returns -EIO
  120  */
  121 static int
  122 iic_dp_aux_get_byte(device_t idev, u8 *byte_ret)
  123 {
  124         struct iic_dp_aux_data *aux_data;
  125         int ret;
  126 
  127         aux_data = device_get_softc(idev);
  128 
  129         if (!aux_data->running)
  130                 return (-EIO);
  131 
  132         ret = iic_dp_aux_transaction(idev, MODE_I2C_READ, 0, byte_ret);
  133         return (ret);
  134 }
  135 
  136 static int
  137 iic_dp_aux_xfer(device_t idev, struct iic_msg *msgs, uint32_t num)
  138 {
  139         u8 *buf;
  140         int b, m, ret;
  141         u16 len;
  142         bool reading;
  143 
  144         ret = 0;
  145         reading = false;
  146 
  147         for (m = 0; m < num; m++) {
  148                 len = msgs[m].len;
  149                 buf = msgs[m].buf;
  150                 reading = (msgs[m].flags & IIC_M_RD) != 0;
  151                 ret = iic_dp_aux_address(idev, msgs[m].slave >> 1, reading);
  152                 if (ret < 0)
  153                         break;
  154                 if (reading) {
  155                         for (b = 0; b < len; b++) {
  156                                 ret = iic_dp_aux_get_byte(idev, &buf[b]);
  157                                 if (ret != 0)
  158                                         break;
  159                         }
  160                 } else {
  161                         for (b = 0; b < len; b++) {
  162                                 ret = iic_dp_aux_put_byte(idev, buf[b]);
  163                                 if (ret < 0)
  164                                         break;
  165                         }
  166                 }
  167                 if (ret != 0)
  168                         break;
  169         }
  170         iic_dp_aux_stop(idev, reading);
  171         DRM_DEBUG_KMS("dp_aux_xfer return %d\n", ret);
  172         return (-ret);
  173 }
  174 
  175 static void
  176 iic_dp_aux_reset_bus(device_t idev)
  177 {
  178 
  179         (void)iic_dp_aux_address(idev, 0, false);
  180         (void)iic_dp_aux_stop(idev, false);
  181 }
  182 
  183 static int
  184 iic_dp_aux_reset(device_t idev, u_char speed, u_char addr, u_char *oldaddr)
  185 {
  186 
  187         iic_dp_aux_reset_bus(idev);
  188         return (0);
  189 }
  190 
  191 static int
  192 iic_dp_aux_prepare_bus(device_t idev)
  193 {
  194 
  195         /* adapter->retries = 3; */
  196         iic_dp_aux_reset_bus(idev);
  197         return (0);
  198 }
  199 
  200 static int
  201 iic_dp_aux_probe(device_t idev)
  202 {
  203 
  204         return (BUS_PROBE_DEFAULT);
  205 }
  206 
  207 static int
  208 iic_dp_aux_attach(device_t idev)
  209 {
  210         struct iic_dp_aux_data *aux_data;
  211 
  212         aux_data = device_get_softc(idev);
  213         aux_data->port = device_add_child(idev, "iicbus", -1);
  214         if (aux_data->port == NULL)
  215                 return (ENXIO);
  216         device_quiet(aux_data->port);
  217         bus_generic_attach(idev);
  218         return (0);
  219 }
  220 
  221 int
  222 iic_dp_aux_add_bus(device_t dev, const char *name,
  223     int (*ch)(device_t idev, int mode, uint8_t write_byte, uint8_t *read_byte),
  224     void *priv, device_t *bus, device_t *adapter)
  225 {
  226         device_t ibus;
  227         struct iic_dp_aux_data *data;
  228         int idx, error;
  229         static int dp_bus_counter;
  230 
  231         bus_topo_lock();
  232 
  233         idx = atomic_fetchadd_int(&dp_bus_counter, 1);
  234         ibus = device_add_child(dev, "drm_iic_dp_aux", idx);
  235         if (ibus == NULL) {
  236                 bus_topo_unlock();
  237                 DRM_ERROR("drm_iic_dp_aux bus %d creation error\n", idx);
  238                 return (-ENXIO);
  239         }
  240         device_quiet(ibus);
  241         error = device_probe_and_attach(ibus);
  242         if (error != 0) {
  243                 device_delete_child(dev, ibus);
  244                 bus_topo_unlock();
  245                 DRM_ERROR("drm_iic_dp_aux bus %d attach failed, %d\n",
  246                     idx, error);
  247                 return (-error);
  248         }
  249         data = device_get_softc(ibus);
  250         data->running = false;
  251         data->address = 0;
  252         data->aux_ch = ch;
  253         data->priv = priv;
  254         error = iic_dp_aux_prepare_bus(ibus);
  255         if (error == 0) {
  256                 *bus = ibus;
  257                 *adapter = data->port;
  258         }
  259         bus_topo_unlock();
  260         return (-error);
  261 }
  262 
  263 static device_method_t drm_iic_dp_aux_methods[] = {
  264         DEVMETHOD(device_probe,         iic_dp_aux_probe),
  265         DEVMETHOD(device_attach,        iic_dp_aux_attach),
  266         DEVMETHOD(device_detach,        bus_generic_detach),
  267         DEVMETHOD(iicbus_reset,         iic_dp_aux_reset),
  268         DEVMETHOD(iicbus_transfer,      iic_dp_aux_xfer),
  269         DEVMETHOD_END
  270 };
  271 
  272 static driver_t drm_iic_dp_aux_driver = {
  273         "drm_iic_dp_aux",
  274         drm_iic_dp_aux_methods,
  275         sizeof(struct iic_dp_aux_data)
  276 };
  277 
  278 DRIVER_MODULE_ORDERED(drm_iic_dp_aux, drmn, drm_iic_dp_aux_driver, 0, 0,
  279     SI_ORDER_SECOND);

Cache object: d55a677ddb8cdc2a718c6f7aba6781a7


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.