linux/drivers/gpu/drm/bridge/sii902x.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2016 Atmel
   3 *                    Bo Shen <voice.shen@atmel.com>
   4 *
   5 * Authors:           Bo Shen <voice.shen@atmel.com>
   6 *                    Boris Brezillon <boris.brezillon@free-electrons.com>
   7 *                    Wu, Songjun <Songjun.Wu@atmel.com>
   8 *
   9 *
  10 * Copyright (C) 2010-2011 Freescale Semiconductor, Inc. All Rights Reserved.
  11 *
  12 * This program is free software; you can redistribute it and/or modify
  13 * it under the terms of the GNU General Public License as published by
  14 * the Free Software Foundation; either version 2 of the License, or
  15 * (at your option) any later version.
  16 *
  17 * This program is distributed in the hope that it will be useful,
  18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20 * GNU General Public License for more details.
  21 */
  22
  23#include <linux/gpio/consumer.h>
  24#include <linux/i2c.h>
  25#include <linux/module.h>
  26#include <linux/regmap.h>
  27
  28#include <drm/drmP.h>
  29#include <drm/drm_atomic_helper.h>
  30#include <drm/drm_crtc_helper.h>
  31#include <drm/drm_edid.h>
  32
  33#define SII902X_TPI_VIDEO_DATA                  0x0
  34
  35#define SII902X_TPI_PIXEL_REPETITION            0x8
  36#define SII902X_TPI_AVI_PIXEL_REP_BUS_24BIT     BIT(5)
  37#define SII902X_TPI_AVI_PIXEL_REP_RISING_EDGE   BIT(4)
  38#define SII902X_TPI_AVI_PIXEL_REP_4X            3
  39#define SII902X_TPI_AVI_PIXEL_REP_2X            1
  40#define SII902X_TPI_AVI_PIXEL_REP_NONE          0
  41#define SII902X_TPI_CLK_RATIO_HALF              (0 << 6)
  42#define SII902X_TPI_CLK_RATIO_1X                (1 << 6)
  43#define SII902X_TPI_CLK_RATIO_2X                (2 << 6)
  44#define SII902X_TPI_CLK_RATIO_4X                (3 << 6)
  45
  46#define SII902X_TPI_AVI_IN_FORMAT               0x9
  47#define SII902X_TPI_AVI_INPUT_BITMODE_12BIT     BIT(7)
  48#define SII902X_TPI_AVI_INPUT_DITHER            BIT(6)
  49#define SII902X_TPI_AVI_INPUT_RANGE_LIMITED     (2 << 2)
  50#define SII902X_TPI_AVI_INPUT_RANGE_FULL        (1 << 2)
  51#define SII902X_TPI_AVI_INPUT_RANGE_AUTO        (0 << 2)
  52#define SII902X_TPI_AVI_INPUT_COLORSPACE_BLACK  (3 << 0)
  53#define SII902X_TPI_AVI_INPUT_COLORSPACE_YUV422 (2 << 0)
  54#define SII902X_TPI_AVI_INPUT_COLORSPACE_YUV444 (1 << 0)
  55#define SII902X_TPI_AVI_INPUT_COLORSPACE_RGB    (0 << 0)
  56
  57#define SII902X_TPI_AVI_INFOFRAME               0x0c
  58
  59#define SII902X_SYS_CTRL_DATA                   0x1a
  60#define SII902X_SYS_CTRL_PWR_DWN                BIT(4)
  61#define SII902X_SYS_CTRL_AV_MUTE                BIT(3)
  62#define SII902X_SYS_CTRL_DDC_BUS_REQ            BIT(2)
  63#define SII902X_SYS_CTRL_DDC_BUS_GRTD           BIT(1)
  64#define SII902X_SYS_CTRL_OUTPUT_MODE            BIT(0)
  65#define SII902X_SYS_CTRL_OUTPUT_HDMI            1
  66#define SII902X_SYS_CTRL_OUTPUT_DVI             0
  67
  68#define SII902X_REG_CHIPID(n)                   (0x1b + (n))
  69
  70#define SII902X_PWR_STATE_CTRL                  0x1e
  71#define SII902X_AVI_POWER_STATE_MSK             GENMASK(1, 0)
  72#define SII902X_AVI_POWER_STATE_D(l)            ((l) & SII902X_AVI_POWER_STATE_MSK)
  73
  74#define SII902X_INT_ENABLE                      0x3c
  75#define SII902X_INT_STATUS                      0x3d
  76#define SII902X_HOTPLUG_EVENT                   BIT(0)
  77#define SII902X_PLUGGED_STATUS                  BIT(2)
  78
  79#define SII902X_REG_TPI_RQB                     0xc7
  80
  81#define SII902X_I2C_BUS_ACQUISITION_TIMEOUT_MS  500
  82
  83struct sii902x {
  84        struct i2c_client *i2c;
  85        struct regmap *regmap;
  86        struct drm_bridge bridge;
  87        struct drm_connector connector;
  88        struct gpio_desc *reset_gpio;
  89};
  90
  91static inline struct sii902x *bridge_to_sii902x(struct drm_bridge *bridge)
  92{
  93        return container_of(bridge, struct sii902x, bridge);
  94}
  95
  96static inline struct sii902x *connector_to_sii902x(struct drm_connector *con)
  97{
  98        return container_of(con, struct sii902x, connector);
  99}
 100
 101static void sii902x_reset(struct sii902x *sii902x)
 102{
 103        if (!sii902x->reset_gpio)
 104                return;
 105
 106        gpiod_set_value(sii902x->reset_gpio, 1);
 107
 108        /* The datasheet says treset-min = 100us. Make it 150us to be sure. */
 109        usleep_range(150, 200);
 110
 111        gpiod_set_value(sii902x->reset_gpio, 0);
 112}
 113
 114static enum drm_connector_status
 115sii902x_connector_detect(struct drm_connector *connector, bool force)
 116{
 117        struct sii902x *sii902x = connector_to_sii902x(connector);
 118        unsigned int status;
 119
 120        regmap_read(sii902x->regmap, SII902X_INT_STATUS, &status);
 121
 122        return (status & SII902X_PLUGGED_STATUS) ?
 123               connector_status_connected : connector_status_disconnected;
 124}
 125
 126static const struct drm_connector_funcs sii902x_connector_funcs = {
 127        .detect = sii902x_connector_detect,
 128        .fill_modes = drm_helper_probe_single_connector_modes,
 129        .destroy = drm_connector_cleanup,
 130        .reset = drm_atomic_helper_connector_reset,
 131        .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
 132        .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
 133};
 134
 135static int sii902x_get_modes(struct drm_connector *connector)
 136{
 137        struct sii902x *sii902x = connector_to_sii902x(connector);
 138        struct regmap *regmap = sii902x->regmap;
 139        u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24;
 140        unsigned long timeout;
 141        unsigned int status;
 142        struct edid *edid;
 143        int num = 0;
 144        int ret;
 145
 146        ret = regmap_update_bits(regmap, SII902X_SYS_CTRL_DATA,
 147                                 SII902X_SYS_CTRL_DDC_BUS_REQ,
 148                                 SII902X_SYS_CTRL_DDC_BUS_REQ);
 149        if (ret)
 150                return ret;
 151
 152        timeout = jiffies +
 153                  msecs_to_jiffies(SII902X_I2C_BUS_ACQUISITION_TIMEOUT_MS);
 154        do {
 155                ret = regmap_read(regmap, SII902X_SYS_CTRL_DATA, &status);
 156                if (ret)
 157                        return ret;
 158        } while (!(status & SII902X_SYS_CTRL_DDC_BUS_GRTD) &&
 159                 time_before(jiffies, timeout));
 160
 161        if (!(status & SII902X_SYS_CTRL_DDC_BUS_GRTD)) {
 162                dev_err(&sii902x->i2c->dev, "failed to acquire the i2c bus\n");
 163                return -ETIMEDOUT;
 164        }
 165
 166        ret = regmap_write(regmap, SII902X_SYS_CTRL_DATA, status);
 167        if (ret)
 168                return ret;
 169
 170        edid = drm_get_edid(connector, sii902x->i2c->adapter);
 171        drm_mode_connector_update_edid_property(connector, edid);
 172        if (edid) {
 173                num = drm_add_edid_modes(connector, edid);
 174                kfree(edid);
 175        }
 176
 177        ret = drm_display_info_set_bus_formats(&connector->display_info,
 178                                               &bus_format, 1);
 179        if (ret)
 180                return ret;
 181
 182        ret = regmap_read(regmap, SII902X_SYS_CTRL_DATA, &status);
 183        if (ret)
 184                return ret;
 185
 186        ret = regmap_update_bits(regmap, SII902X_SYS_CTRL_DATA,
 187                                 SII902X_SYS_CTRL_DDC_BUS_REQ |
 188                                 SII902X_SYS_CTRL_DDC_BUS_GRTD, 0);
 189        if (ret)
 190                return ret;
 191
 192        timeout = jiffies +
 193                  msecs_to_jiffies(SII902X_I2C_BUS_ACQUISITION_TIMEOUT_MS);
 194        do {
 195                ret = regmap_read(regmap, SII902X_SYS_CTRL_DATA, &status);
 196                if (ret)
 197                        return ret;
 198        } while (status & (SII902X_SYS_CTRL_DDC_BUS_REQ |
 199                           SII902X_SYS_CTRL_DDC_BUS_GRTD) &&
 200                 time_before(jiffies, timeout));
 201
 202        if (status & (SII902X_SYS_CTRL_DDC_BUS_REQ |
 203                      SII902X_SYS_CTRL_DDC_BUS_GRTD)) {
 204                dev_err(&sii902x->i2c->dev, "failed to release the i2c bus\n");
 205                return -ETIMEDOUT;
 206        }
 207
 208        return num;
 209}
 210
 211static enum drm_mode_status sii902x_mode_valid(struct drm_connector *connector,
 212                                               struct drm_display_mode *mode)
 213{
 214        /* TODO: check mode */
 215
 216        return MODE_OK;
 217}
 218
 219static const struct drm_connector_helper_funcs sii902x_connector_helper_funcs = {
 220        .get_modes = sii902x_get_modes,
 221        .mode_valid = sii902x_mode_valid,
 222};
 223
 224static void sii902x_bridge_disable(struct drm_bridge *bridge)
 225{
 226        struct sii902x *sii902x = bridge_to_sii902x(bridge);
 227
 228        regmap_update_bits(sii902x->regmap, SII902X_SYS_CTRL_DATA,
 229                           SII902X_SYS_CTRL_PWR_DWN,
 230                           SII902X_SYS_CTRL_PWR_DWN);
 231}
 232
 233static void sii902x_bridge_enable(struct drm_bridge *bridge)
 234{
 235        struct sii902x *sii902x = bridge_to_sii902x(bridge);
 236
 237        regmap_update_bits(sii902x->regmap, SII902X_PWR_STATE_CTRL,
 238                           SII902X_AVI_POWER_STATE_MSK,
 239                           SII902X_AVI_POWER_STATE_D(0));
 240        regmap_update_bits(sii902x->regmap, SII902X_SYS_CTRL_DATA,
 241                           SII902X_SYS_CTRL_PWR_DWN, 0);
 242}
 243
 244static void sii902x_bridge_mode_set(struct drm_bridge *bridge,
 245                                    struct drm_display_mode *mode,
 246                                    struct drm_display_mode *adj)
 247{
 248        struct sii902x *sii902x = bridge_to_sii902x(bridge);
 249        struct regmap *regmap = sii902x->regmap;
 250        u8 buf[HDMI_INFOFRAME_SIZE(AVI)];
 251        struct hdmi_avi_infoframe frame;
 252        int ret;
 253
 254        buf[0] = adj->clock;
 255        buf[1] = adj->clock >> 8;
 256        buf[2] = adj->vrefresh;
 257        buf[3] = 0x00;
 258        buf[4] = adj->hdisplay;
 259        buf[5] = adj->hdisplay >> 8;
 260        buf[6] = adj->vdisplay;
 261        buf[7] = adj->vdisplay >> 8;
 262        buf[8] = SII902X_TPI_CLK_RATIO_1X | SII902X_TPI_AVI_PIXEL_REP_NONE |
 263                 SII902X_TPI_AVI_PIXEL_REP_BUS_24BIT;
 264        buf[9] = SII902X_TPI_AVI_INPUT_RANGE_AUTO |
 265                 SII902X_TPI_AVI_INPUT_COLORSPACE_RGB;
 266
 267        ret = regmap_bulk_write(regmap, SII902X_TPI_VIDEO_DATA, buf, 10);
 268        if (ret)
 269                return;
 270
 271        ret = drm_hdmi_avi_infoframe_from_display_mode(&frame, adj, false);
 272        if (ret < 0) {
 273                DRM_ERROR("couldn't fill AVI infoframe\n");
 274                return;
 275        }
 276
 277        ret = hdmi_avi_infoframe_pack(&frame, buf, sizeof(buf));
 278        if (ret < 0) {
 279                DRM_ERROR("failed to pack AVI infoframe: %d\n", ret);
 280                return;
 281        }
 282
 283        /* Do not send the infoframe header, but keep the CRC field. */
 284        regmap_bulk_write(regmap, SII902X_TPI_AVI_INFOFRAME,
 285                          buf + HDMI_INFOFRAME_HEADER_SIZE - 1,
 286                          HDMI_AVI_INFOFRAME_SIZE + 1);
 287}
 288
 289static int sii902x_bridge_attach(struct drm_bridge *bridge)
 290{
 291        struct sii902x *sii902x = bridge_to_sii902x(bridge);
 292        struct drm_device *drm = bridge->dev;
 293        int ret;
 294
 295        drm_connector_helper_add(&sii902x->connector,
 296                                 &sii902x_connector_helper_funcs);
 297
 298        if (!drm_core_check_feature(drm, DRIVER_ATOMIC)) {
 299                dev_err(&sii902x->i2c->dev,
 300                        "sii902x driver is only compatible with DRM devices supporting atomic updates\n");
 301                return -ENOTSUPP;
 302        }
 303
 304        ret = drm_connector_init(drm, &sii902x->connector,
 305                                 &sii902x_connector_funcs,
 306                                 DRM_MODE_CONNECTOR_HDMIA);
 307        if (ret)
 308                return ret;
 309
 310        if (sii902x->i2c->irq > 0)
 311                sii902x->connector.polled = DRM_CONNECTOR_POLL_HPD;
 312        else
 313                sii902x->connector.polled = DRM_CONNECTOR_POLL_CONNECT;
 314
 315        drm_mode_connector_attach_encoder(&sii902x->connector, bridge->encoder);
 316
 317        return 0;
 318}
 319
 320static const struct drm_bridge_funcs sii902x_bridge_funcs = {
 321        .attach = sii902x_bridge_attach,
 322        .mode_set = sii902x_bridge_mode_set,
 323        .disable = sii902x_bridge_disable,
 324        .enable = sii902x_bridge_enable,
 325};
 326
 327static const struct regmap_range sii902x_volatile_ranges[] = {
 328        { .range_min = 0, .range_max = 0xff },
 329};
 330
 331static const struct regmap_access_table sii902x_volatile_table = {
 332        .yes_ranges = sii902x_volatile_ranges,
 333        .n_yes_ranges = ARRAY_SIZE(sii902x_volatile_ranges),
 334};
 335
 336static const struct regmap_config sii902x_regmap_config = {
 337        .reg_bits = 8,
 338        .val_bits = 8,
 339        .volatile_table = &sii902x_volatile_table,
 340        .cache_type = REGCACHE_NONE,
 341};
 342
 343static irqreturn_t sii902x_interrupt(int irq, void *data)
 344{
 345        struct sii902x *sii902x = data;
 346        unsigned int status = 0;
 347
 348        regmap_read(sii902x->regmap, SII902X_INT_STATUS, &status);
 349        regmap_write(sii902x->regmap, SII902X_INT_STATUS, status);
 350
 351        if ((status & SII902X_HOTPLUG_EVENT) && sii902x->bridge.dev)
 352                drm_helper_hpd_irq_event(sii902x->bridge.dev);
 353
 354        return IRQ_HANDLED;
 355}
 356
 357static int sii902x_probe(struct i2c_client *client,
 358                         const struct i2c_device_id *id)
 359{
 360        struct device *dev = &client->dev;
 361        unsigned int status = 0;
 362        struct sii902x *sii902x;
 363        u8 chipid[4];
 364        int ret;
 365
 366        sii902x = devm_kzalloc(dev, sizeof(*sii902x), GFP_KERNEL);
 367        if (!sii902x)
 368                return -ENOMEM;
 369
 370        sii902x->i2c = client;
 371        sii902x->regmap = devm_regmap_init_i2c(client, &sii902x_regmap_config);
 372        if (IS_ERR(sii902x->regmap))
 373                return PTR_ERR(sii902x->regmap);
 374
 375        sii902x->reset_gpio = devm_gpiod_get_optional(dev, "reset",
 376                                                      GPIOD_OUT_LOW);
 377        if (IS_ERR(sii902x->reset_gpio)) {
 378                dev_err(dev, "Failed to retrieve/request reset gpio: %ld\n",
 379                        PTR_ERR(sii902x->reset_gpio));
 380                return PTR_ERR(sii902x->reset_gpio);
 381        }
 382
 383        sii902x_reset(sii902x);
 384
 385        ret = regmap_write(sii902x->regmap, SII902X_REG_TPI_RQB, 0x0);
 386        if (ret)
 387                return ret;
 388
 389        ret = regmap_bulk_read(sii902x->regmap, SII902X_REG_CHIPID(0),
 390                               &chipid, 4);
 391        if (ret) {
 392                dev_err(dev, "regmap_read failed %d\n", ret);
 393                return ret;
 394        }
 395
 396        if (chipid[0] != 0xb0) {
 397                dev_err(dev, "Invalid chipid: %02x (expecting 0xb0)\n",
 398                        chipid[0]);
 399                return -EINVAL;
 400        }
 401
 402        /* Clear all pending interrupts */
 403        regmap_read(sii902x->regmap, SII902X_INT_STATUS, &status);
 404        regmap_write(sii902x->regmap, SII902X_INT_STATUS, status);
 405
 406        if (client->irq > 0) {
 407                regmap_write(sii902x->regmap, SII902X_INT_ENABLE,
 408                             SII902X_HOTPLUG_EVENT);
 409
 410                ret = devm_request_threaded_irq(dev, client->irq, NULL,
 411                                                sii902x_interrupt,
 412                                                IRQF_ONESHOT, dev_name(dev),
 413                                                sii902x);
 414                if (ret)
 415                        return ret;
 416        }
 417
 418        sii902x->bridge.funcs = &sii902x_bridge_funcs;
 419        sii902x->bridge.of_node = dev->of_node;
 420        drm_bridge_add(&sii902x->bridge);
 421
 422        i2c_set_clientdata(client, sii902x);
 423
 424        return 0;
 425}
 426
 427static int sii902x_remove(struct i2c_client *client)
 428
 429{
 430        struct sii902x *sii902x = i2c_get_clientdata(client);
 431
 432        drm_bridge_remove(&sii902x->bridge);
 433
 434        return 0;
 435}
 436
 437static const struct of_device_id sii902x_dt_ids[] = {
 438        { .compatible = "sil,sii9022", },
 439        { }
 440};
 441MODULE_DEVICE_TABLE(of, sii902x_dt_ids);
 442
 443static const struct i2c_device_id sii902x_i2c_ids[] = {
 444        { "sii9022", 0 },
 445        { },
 446};
 447MODULE_DEVICE_TABLE(i2c, sii902x_i2c_ids);
 448
 449static struct i2c_driver sii902x_driver = {
 450        .probe = sii902x_probe,
 451        .remove = sii902x_remove,
 452        .driver = {
 453                .name = "sii902x",
 454                .of_match_table = sii902x_dt_ids,
 455        },
 456        .id_table = sii902x_i2c_ids,
 457};
 458module_i2c_driver(sii902x_driver);
 459
 460MODULE_AUTHOR("Boris Brezillon <boris.brezillon@free-electrons.com>");
 461MODULE_DESCRIPTION("SII902x RGB -> HDMI bridges");
 462MODULE_LICENSE("GPL");
 463