123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210 |
- /**************************************************************************
- Copyright 2006 Dave Airlie <airlied@linux.ie>
- All Rights Reserved.
- Permission is hereby granted, free of charge, to any person obtaining a
- copy of this software and associated documentation files (the "Software"),
- to deal in the Software without restriction, including without limitation
- on the rights to use, copy, modify, merge, publish, distribute, sub
- license, and/or sell copies of the Software, and to permit persons to whom
- the Software is furnished to do so, subject to the following conditions:
- The above copyright notice and this permission notice (including the next
- paragraph) shall be included in all copies or substantial portions of the
- Software.
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
- THE COPYRIGHT HOLDERS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
- DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
- OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
- USE OR OTHER DEALINGS IN THE SOFTWARE.
- **************************************************************************/
- #include <linux/module.h>
- #include <linux/kernel.h>
- #include <linux/delay.h>
- #include <linux/pci.h>
- #include <linux/fb.h>
- #include <linux/i2c.h>
- #include <linux/i2c-algo-bit.h>
- #include <asm/io.h>
- #include "intelfb.h"
- #include "intelfbhw.h"
- /* bit locations in the registers */
- #define SCL_DIR_MASK 0x0001
- #define SCL_DIR 0x0002
- #define SCL_VAL_MASK 0x0004
- #define SCL_VAL_OUT 0x0008
- #define SCL_VAL_IN 0x0010
- #define SDA_DIR_MASK 0x0100
- #define SDA_DIR 0x0200
- #define SDA_VAL_MASK 0x0400
- #define SDA_VAL_OUT 0x0800
- #define SDA_VAL_IN 0x1000
- static void intelfb_gpio_setscl(void *data, int state)
- {
- struct intelfb_i2c_chan *chan = data;
- struct intelfb_info *dinfo = chan->dinfo;
- u32 val;
- OUTREG(chan->reg, (state ? SCL_VAL_OUT : 0) |
- SCL_DIR | SCL_DIR_MASK | SCL_VAL_MASK);
- val = INREG(chan->reg);
- }
- static void intelfb_gpio_setsda(void *data, int state)
- {
- struct intelfb_i2c_chan *chan = data;
- struct intelfb_info *dinfo = chan->dinfo;
- u32 val;
- OUTREG(chan->reg, (state ? SDA_VAL_OUT : 0) |
- SDA_DIR | SDA_DIR_MASK | SDA_VAL_MASK);
- val = INREG(chan->reg);
- }
- static int intelfb_gpio_getscl(void *data)
- {
- struct intelfb_i2c_chan *chan = data;
- struct intelfb_info *dinfo = chan->dinfo;
- u32 val;
- OUTREG(chan->reg, SCL_DIR_MASK);
- OUTREG(chan->reg, 0);
- val = INREG(chan->reg);
- return ((val & SCL_VAL_IN) != 0);
- }
- static int intelfb_gpio_getsda(void *data)
- {
- struct intelfb_i2c_chan *chan = data;
- struct intelfb_info *dinfo = chan->dinfo;
- u32 val;
- OUTREG(chan->reg, SDA_DIR_MASK);
- OUTREG(chan->reg, 0);
- val = INREG(chan->reg);
- return ((val & SDA_VAL_IN) != 0);
- }
- static int intelfb_setup_i2c_bus(struct intelfb_info *dinfo,
- struct intelfb_i2c_chan *chan,
- const u32 reg, const char *name,
- int class)
- {
- int rc;
- chan->dinfo = dinfo;
- chan->reg = reg;
- snprintf(chan->adapter.name, sizeof(chan->adapter.name),
- "intelfb %s", name);
- chan->adapter.class = class;
- chan->adapter.owner = THIS_MODULE;
- chan->adapter.algo_data = &chan->algo;
- chan->adapter.dev.parent = &chan->dinfo->pdev->dev;
- chan->algo.setsda = intelfb_gpio_setsda;
- chan->algo.setscl = intelfb_gpio_setscl;
- chan->algo.getsda = intelfb_gpio_getsda;
- chan->algo.getscl = intelfb_gpio_getscl;
- chan->algo.udelay = 40;
- chan->algo.timeout = 20;
- chan->algo.data = chan;
- i2c_set_adapdata(&chan->adapter, chan);
- /* Raise SCL and SDA */
- intelfb_gpio_setsda(chan, 1);
- intelfb_gpio_setscl(chan, 1);
- udelay(20);
- rc = i2c_bit_add_bus(&chan->adapter);
- if (rc == 0)
- DBG_MSG("I2C bus %s registered.\n", name);
- else
- WRN_MSG("Failed to register I2C bus %s.\n", name);
- return rc;
- }
- void intelfb_create_i2c_busses(struct intelfb_info *dinfo)
- {
- int i = 0;
- /* everyone has at least a single analog output */
- dinfo->num_outputs = 1;
- dinfo->output[i].type = INTELFB_OUTPUT_ANALOG;
- /* setup the DDC bus for analog output */
- intelfb_setup_i2c_bus(dinfo, &dinfo->output[i].ddc_bus, GPIOA,
- "CRTDDC_A", I2C_CLASS_DDC);
- i++;
- /* need to add the output busses for each device
- - this function is very incomplete
- - i915GM has LVDS and TVOUT for example
- */
- switch(dinfo->chipset) {
- case INTEL_830M:
- case INTEL_845G:
- case INTEL_854:
- case INTEL_855GM:
- case INTEL_865G:
- dinfo->output[i].type = INTELFB_OUTPUT_DVO;
- intelfb_setup_i2c_bus(dinfo, &dinfo->output[i].ddc_bus,
- GPIOD, "DVODDC_D", I2C_CLASS_DDC);
- intelfb_setup_i2c_bus(dinfo, &dinfo->output[i].i2c_bus,
- GPIOE, "DVOI2C_E", 0);
- i++;
- break;
- case INTEL_915G:
- case INTEL_915GM:
- /* has some LVDS + tv-out */
- case INTEL_945G:
- case INTEL_945GM:
- case INTEL_945GME:
- case INTEL_965G:
- case INTEL_965GM:
- /* SDVO ports have a single control bus - 2 devices */
- dinfo->output[i].type = INTELFB_OUTPUT_SDVO;
- intelfb_setup_i2c_bus(dinfo, &dinfo->output[i].i2c_bus,
- GPIOE, "SDVOCTRL_E", 0);
- /* TODO: initialize the SDVO */
- /* I830SDVOInit(pScrn, i, DVOB); */
- i++;
- /* set up SDVOC */
- dinfo->output[i].type = INTELFB_OUTPUT_SDVO;
- dinfo->output[i].i2c_bus = dinfo->output[i - 1].i2c_bus;
- /* TODO: initialize the SDVO */
- /* I830SDVOInit(pScrn, i, DVOC); */
- i++;
- break;
- }
- dinfo->num_outputs = i;
- }
- void intelfb_delete_i2c_busses(struct intelfb_info *dinfo)
- {
- int i;
- for (i = 0; i < MAX_OUTPUTS; i++) {
- if (dinfo->output[i].i2c_bus.dinfo) {
- i2c_del_adapter(&dinfo->output[i].i2c_bus.adapter);
- dinfo->output[i].i2c_bus.dinfo = NULL;
- }
- if (dinfo->output[i].ddc_bus.dinfo) {
- i2c_del_adapter(&dinfo->output[i].ddc_bus.adapter);
- dinfo->output[i].ddc_bus.dinfo = NULL;
- }
- }
- }
|