From patchwork Sat Jun 8 16:48:55 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: James Simmons X-Patchwork-Id: 2692781 Return-Path: X-Original-To: patchwork-dri-devel@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork1.kernel.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by patchwork1.kernel.org (Postfix) with ESMTP id 5BA0F3FC23 for ; Sat, 8 Jun 2013 16:50:01 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 5C08AE613D for ; Sat, 8 Jun 2013 09:50:01 -0700 (PDT) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from casper.infradead.org (casper.infradead.org [85.118.1.10]) by gabe.freedesktop.org (Postfix) with ESMTP id DF386E6144; Sat, 8 Jun 2013 09:48:57 -0700 (PDT) Received: from jsimmons (helo=localhost) by casper.infradead.org with local-esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1UlMJz-00060N-OO; Sat, 08 Jun 2013 16:48:57 +0000 Date: Sat, 8 Jun 2013 17:48:55 +0100 (BST) From: James Simmons To: DRI development list Subject: [RFC 7/21] DRM: Add VIA DRM driver Message-ID: User-Agent: Alpine 2.03 (LFD 1266 2009-07-14) MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20130608_174855_882858_F4EEF5F8 X-CRM114-Status: GOOD ( 16.25 ) X-Spam-Score: -1.9 (-) X-Spam-Report: SpamAssassin version 3.3.2 on casper.infradead.org summary: Content analysis details: (-1.9 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 NO_RELAYS Informational: message was not relayed via SMTP -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] Cc: OpenChrome Development X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.13 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: dri-devel-bounces+patchwork-dri-devel=patchwork.kernel.org@lists.freedesktop.org Errors-To: dri-devel-bounces+patchwork-dri-devel=patchwork.kernel.org@lists.freedesktop.org commit a1296bc36bbc68963ef0294e94bef69ddb998c9a Author: James Simmons Date: Sat Jun 8 08:53:44 2013 -0400 via: i2c handling In order to support EDID retrieval and the via camera on the XO data much be collected over the i2c buses. We use the i2c layer developed by the viafb project. Signed-Off-by: James Simmons diff --git a/drivers/gpu/drm/via/via_i2c.c b/drivers/gpu/drm/via/via_i2c.c new file mode 100644 index 0000000..f4fcdea --- /dev/null +++ b/drivers/gpu/drm/via/via_i2c.c @@ -0,0 +1,204 @@ +/* + * Copyright 2012 James Simmons All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; + * either version 2, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE.See the GNU General Public License + * for more details. + * + * This part was influenced by the via i2c code written for the viafb + * driver by VIA Technologies and S3 Graphics + */ +#include "via_drv.h" + +enum viafb_i2c_adap; + +#include + +#define SERIAL 0 +#define GPIO 1 + +static struct via_i2c_stuff via_i2c_par[5]; + +static void via_i2c_setscl(void *data, int state) +{ + struct via_i2c_stuff *i2c = data; + struct drm_device *dev = i2c_get_adapdata(&i2c->adapter); + struct drm_via_private *dev_priv = dev->dev_private; + u8 value, mask; + + if (i2c->is_active == GPIO) { + mask = state ? BIT(7) : BIT(7) | BIT(5); + value = state ? 0x00 : BIT(7); + } else { + value = state ? BIT(5) : 0x00; + mask = BIT(5); + } + svga_wseq_mask(VGABASE, i2c->i2c_port, value, mask); +} + +static int via_i2c_getscl(void *data) +{ + struct via_i2c_stuff *i2c = data; + struct drm_device *dev = i2c_get_adapdata(&i2c->adapter); + struct drm_via_private *dev_priv = dev->dev_private; + + return (vga_rseq(VGABASE, i2c->i2c_port) & BIT(3)); +} + +static int via_i2c_getsda(void *data) +{ + struct via_i2c_stuff *i2c = data; + struct drm_device *dev = i2c_get_adapdata(&i2c->adapter); + struct drm_via_private *dev_priv = dev->dev_private; + + return (vga_rseq(VGABASE, i2c->i2c_port) & BIT(2)); +} + +static void via_i2c_setsda(void *data, int state) +{ + struct via_i2c_stuff *i2c = data; + struct drm_device *dev = i2c_get_adapdata(&i2c->adapter); + struct drm_via_private *dev_priv = dev->dev_private; + u8 value, mask; + + if (i2c->is_active == GPIO) { + mask = state ? BIT(6) : BIT(6) | BIT(4); + value = state ? 0x00 : BIT(6); + } else { + value = state ? BIT(4) : 0x00; + mask = BIT(4); + } + svga_wseq_mask(VGABASE, i2c->i2c_port, value, mask); +} + +struct i2c_adapter *via_find_ddc_bus(int port) +{ + struct i2c_adapter *adapter = NULL; + int i; + + for (i = 0; i < ARRAY_SIZE(via_i2c_par); i++) { + struct via_i2c_stuff *i2c = &via_i2c_par[i]; + + if (i2c->i2c_port == port) { + adapter = &i2c->adapter; + break; + } + } + return adapter; +} + +static int +create_i2c_bus(struct drm_device *dev, struct via_i2c_stuff *i2c_par) +{ + struct i2c_adapter *adapter = &i2c_par->adapter; + struct i2c_algo_bit_data *algo = &i2c_par->algo; + + algo->setsda = via_i2c_setsda; + algo->setscl = via_i2c_setscl; + algo->getsda = via_i2c_getsda; + algo->getscl = via_i2c_getscl; + algo->udelay = 15; + algo->timeout = usecs_to_jiffies(2200); /* from VESA */ + algo->data = i2c_par; + + sprintf(adapter->name, "via i2c bit bus 0x%02x", i2c_par->i2c_port); + adapter->owner = THIS_MODULE; + adapter->class = I2C_CLASS_DDC; + adapter->algo_data = algo; + i2c_set_adapdata(adapter, dev); + + /* Raise SCL and SDA */ + via_i2c_setsda(i2c_par, 1); + via_i2c_setscl(i2c_par, 1); + udelay(20); + + return i2c_bit_add_bus(adapter); +} + +void +via_i2c_readbytes(struct i2c_adapter *adapter, + u8 slave_addr, char offset, + u8 *buffer, unsigned int size) +{ + u8 out_buf[2]; + u8 in_buf[2]; + struct i2c_msg msgs[] = { + { + .addr = slave_addr, + .flags = 0, + .len = 1, + .buf = out_buf, + }, + { + .addr = slave_addr, + .flags = I2C_M_RD, + .len = size, + .buf = in_buf, + } + }; + + out_buf[0] = offset; + out_buf[1] = 0; + + if (i2c_transfer(adapter, msgs, 2) != 2) + printk(KERN_WARNING "%s failed\n", __func__); + else + *buffer = in_buf[0]; +} + +void +via_i2c_writebytes(struct i2c_adapter *adapter, + u8 slave_addr, char offset, + u8 *data, unsigned int size) +{ + struct i2c_msg msg = { 0 }; + u8 *out_buf; + + out_buf = kzalloc(size + 1, GFP_KERNEL); + out_buf[0] = offset; + memcpy(&out_buf[1], data, size); + msg.addr = slave_addr; + msg.flags = 0; + msg.len = size + 1; + msg.buf = out_buf; + + if (i2c_transfer(adapter, &msg, 1) != 1) + printk(KERN_WARNING "%s failed\n", __func__); + + kfree(out_buf); +} + +int via_i2c_init(struct drm_device *dev) +{ + int types[] = { SERIAL, SERIAL, GPIO, GPIO, GPIO }; + int ports[] = { 0x26, 0x31, 0x25, 0x2C, 0x3D }; + int count = ARRAY_SIZE(via_i2c_par), ret, i; + struct via_i2c_stuff *i2c = via_i2c_par; + + for (i = 0; i < count; i++) { + i2c->is_active = types[i]; + i2c->i2c_port = ports[i]; + + ret = create_i2c_bus(dev, i2c); + if (ret < 0) + DRM_ERROR("cannot create i2c bus %x:%d\n", + ports[i], ret); + i2c++; + } + return 0; +} + +void via_i2c_exit(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(via_i2c_par); i++) + i2c_del_adapter(&via_i2c_par->adapter); +}