首先会在 /arch/x86/kernel/mrst.c 中开始调用:
static int __init mrst_platform_init(void)
3948 {
3949 #ifdef CONFIG_SWITCH_MID
3950 int err;
3951 err = platform_device_register(&switch_device);
3952 if (err < 0)
3953 pr_err("Fail to register switch-mid platform device.\n");
3954 #endif
3955
3956 /* Keep for back compatibility for SFI 0.7 and before */
3957 sfi_table_parse(SFI_SIG_SPIB, NULL, NULL, sfi_parse_spib); //parse spi_table
3958 sfi_table_parse(SFI_SIG_I2CB, NULL, NULL, sfi_parse_i2cb); //parse i2c_table.
3959
3960 /* For SFi 0.8 version */
3961 sfi_table_parse(SFI_SIG_GPIO, NULL, NULL, sfi_parse_gpio); //parse gpio
3962 sfi_table_parse(SFI_SIG_DEVS, NULL, NULL, sfi_parse_devs); //parse devs
3963 return 0;
3964 }
3965 arch_initcall(mrst_platform_init);
-
这里会调用sfi_parse_i2cb, 用来添加信息,注册I2C,内容如下:
static int __init sfi_parse_i2cb(struct sfi_table_header *table) { struct sfi_table_simple *sb; struct sfi_i2c_table_entry *pentry; struct i2c_board_info info; int num, i, busnum; sb = (struct sfi_table_simple *)table; num = SFI_GET_NUM_ENTRIES(sb, struct sfi_i2c_table_entry); pentry = (struct sfi_i2c_table_entry *) sb->pentry; if (num <= 0) return -ENODEV; for (i = 0; i < num; i++, pentry++) { busnum = pentry->host_num; if (busnum >= MRST_I2C_BUSNUM || busnum < 0) continue; memset(&info, 0, sizeof(info)); strncpy(info.type, pentry->name, 16); info.irq = pentry->irq_info; info.addr = pentry->addr; info.platform_data = pentry->dev_info; if (!strcmp(pentry->name, "i2c_max7315")) { strcpy(info.type, "max7315"); max7315_pdata.irq_base = *(int *)pentry->dev_info; max7315_pdata.gpio_base = *((u32 *)pentry->dev_info + 1); info.platform_data = &max7315_pdata; } else if (!strcmp(pentry->name, "i2c_max7315_2")) { strcpy(info.type, "max7315"); max7315_pdata_2.irq_base = *(int *)pentry->dev_info; max7315_pdata_2.gpio_base = *((u32 *)pentry->dev_info + 1); info.platform_data = &max7315_pdata_2; } else if (!strcmp(pentry->name, "i2c_accel")) { strcpy(info.type, "lis3lv02d"); info.platform_data = &lis3lv02d_pdata; } else if (!strcmp(pentry->name, "i2c_als")) { strcpy(info.type, "isl29020"); info.platform_data = NULL; } else if (!strcmp(pentry->name, "i2c_thermal")) { strcpy(info.type, "emc1403"); info.platform_data = NULL; } else if (!strcmp(pentry->name, "i2c_compass")) { strcpy(info.type, "hmc6352"); info.platform_data = NULL; } #ifdef CONFIG_TOUCHSCREEN_ATMEL_MXT224 else if (!strcmp(pentry->name, "mxt224")) { mxt224_platform_data.reset = *(int *)pentry->dev_info; mxt224_platform_data.irq = *((int *)pentry->dev_info + 1); info.platform_data = &mxt224_platform_data; //会调用这个数据 } #endif pr_info("info[%d]: bus = %d, name = %16.16s, irq = 0x%04x, " "addr = 0x%x\n", i, busnum, info.type, info.irq, info.addr); i2c_register_board_info(busnum, &info, 1); //然后注册 } return 0; }
- mxt224_platform_data 数据由这里生成。
#ifdef CONFIG_TOUCHSCREEN_ATMEL_MXT224 static void *mxt224_platform_data_init(void *info) { struct i2c_board_info *i2c_info = (struct i2c_board_info *) info; static struct mxt224_platform_data mxt224_platform_data; int intr = 0; printk(KERN_INFO "In %s.", __func__); memset(&mxt224_platform_data, 0x00, sizeof(struct mxt224_platform_data)); mxt224_platform_data.reset = 129; mxt224_platform_data.irq = 62; i2c_info->irq = (mxt224_platform_data.irq) + MRST_IRQ_OFFSET; return &mxt224_platform_data; } #endif
-
这只是
sfi_parse_i2cb(), 重点还是在 sfi_parse_devs():
static int __init sfi_parse_devs(struct sfi_table_header *table) { struct sfi_table_simple *sb; struct sfi_device_table_entry *pentry; struct spi_board_info spi_info; struct i2c_board_info i2c_info; struct hsi_board_info hsi_info; struct sd_board_info sd_info; struct platform_device *pdev; int num, i, bus; int ioapic; struct io_apic_irq_attr irq_attr; sb = (struct sfi_table_simple *)table; num = SFI_GET_NUM_ENTRIES(sb, struct sfi_device_table_entry); pentry = (struct sfi_device_table_entry *)sb->pentry; for (i = 0; i < num; i++, pentry++) { if (pentry->irq != (u8)0xff) { /* native RTE case */ /* these SPI2 devices are not exposed to system as PCI * devices, but they have separate RTE entry in IOAPIC * so we have to enable them one by one here */ ioapic = mp_find_ioapic(pentry->irq); irq_attr.ioapic = ioapic; irq_attr.ioapic_pin = pentry->irq; irq_attr.trigger = 1; irq_attr.polarity = 1; io_apic_set_pci_routing(NULL, pentry->irq, &irq_attr); } printk(KERN_DEBUG, "Srini: sfi_parse_devs pentry->type %d\n",pentry->type); switch (pentry->type) { case SFI_DEV_TYPE_IPC: /* ID as IRQ is a hack that will go away */ pdev = platform_device_alloc(pentry->name, pentry->irq); if (pdev == NULL) { pr_err("out of memory for SFI platform device '%s'.\n", pentry->name); continue; } /* add msic_audio resource */ if (strcmp(pentry->name, "msic_audio") == 0) { static struct resource res[] = { { .name = "IRQ", .flags = IORESOURCE_IRQ, }, { .name = "IRQ_BASE", .flags = IORESOURCE_MEM, } }; res[0].start = pentry->irq; res[1].start = 0xFFFF7FCD; res[1].end = 0xFFFF7FCD; platform_device_add_resources(pdev, res, 2); } else { install_irq_resource(pdev, pentry->irq); } pr_info("info[%2d]: IPC bus, name = %16.16s, " "irq = 0x%2x\n", i, pentry->name, pentry->irq); sfi_handle_ipc_dev(pdev); break; case SFI_DEV_TYPE_SPI: memset(&spi_info, 0, sizeof(spi_info)); strncpy(spi_info.modalias, pentry->name, 16); spi_info.irq = pentry->irq; spi_info.bus_num = pentry->host_num; spi_info.chip_select = pentry->addr; spi_info.max_speed_hz = pentry->max_freq; pr_info("info[%2d]: SPI bus = %d, name = %16.16s, " "irq = 0x%2x, max_freq = %d, cs = %d\n", i, spi_info.bus_num, spi_info.modalias, spi_info.irq, spi_info.max_speed_hz, spi_info.chip_select); sfi_handle_spi_dev(&spi_info); break; case SFI_DEV_TYPE_I2C: //parse i2c 设备 memset(&i2c_info, 0, sizeof(i2c_info)); bus = pentry->host_num; strncpy(i2c_info.type, pentry->name, 16); i2c_info.irq = pentry->irq; i2c_info.addr = pentry->addr; pr_info("info[%2d]: I2C bus = %d, name = %16.16s, " "irq = 0x%2x, addr = 0x%x\n", i, bus, i2c_info.type, i2c_info.irq, i2c_info.addr); if (!strcmp(i2c_info.type, "i2c_ledflash")) break; #if 0 if (!strcmp(i2c_info.type, "lm3555")) strncpy(i2c_info.type, "as3645a", 16); #endif /* Ignore all sensors info for PR2 */ if (mfld_board_type() == MFLD_BOARD_PR2) if (bus == 5 || bus == 0) break; sfi_handle_i2c_dev(bus, &i2c_info); // sfi 总线来处理 I2C 总线 设备 break; case SFI_DEV_TYPE_SD: memset(&sd_info, 0, sizeof(sd_info)); strncpy(sd_info.name, pentry->name, 16); sd_info.bus_num = pentry->host_num; sd_info.board_ref_clock = pentry->max_freq; sd_info.addr = pentry->addr; pr_info("info[%2d]: SDIO bus = %d, name = %16.16s, " "ref_clock = %d, addr =0x%x\n", i, sd_info.bus_num, sd_info.name, sd_info.board_ref_clock, sd_info.addr); sfi_handle_sd_dev(&sd_info); break; case SFI_DEV_TYPE_HSI: memset(&hsi_info, 0, sizeof(hsi_info)); hsi_info.name = kzalloc(16, GFP_KERNEL); if (hsi_info.name == NULL) { pr_err("out of memory for HSI device '%s'.\n", pentry->name); continue; } strncpy((char *)hsi_info.name, pentry->name, 16); hsi_info.hsi_id = pentry->host_num; hsi_info.port = pentry->addr; pr_info("info[%2d]: HSI bus = %d, name = %16.16s, " "port = %d\n", i, hsi_info.hsi_id, hsi_info.name, hsi_info.port); sfi_handle_hsi_dev(&hsi_info); break; case SFI_DEV_TYPE_UART: default: ; } } return 0; } sfi_handle_i2c_dev(bus, &i2c_info); // sfi 总线来处理 I2C 总线 设备 static void sfi_handle_i2c_dev(int bus, struct i2c_board_info *i2c_info) { const struct devs_id *dev = device_ids; const struct intel_v4l2_subdev_id *vdev = v4l2_ids; void *pdata = NULL; while (dev->name[0]) { if (dev->type == SFI_DEV_TYPE_I2C && !strncmp(dev->name, i2c_info->type, 16)) { pdata = dev->get_platform_data(i2c_info); break; } dev++; } i2c_info->platform_data = pdata; while (vdev->name[0]) { if (!strncmp(vdev->name, i2c_info->type, 16)) { intel_ignore_i2c_device_register(bus, i2c_info); return; } vdev++; } if (dev->delay) intel_delayed_i2c_device_register(bus, i2c_info); else i2c_register_board_info(bus, i2c_info, 1); }
- 最重要的各种类型的设备表:
static const struct devs_id device_ids[] = { {"pmic_gpio", SFI_DEV_TYPE_SPI, 1, &pmic_gpio_platform_data}, {"pmic_gpio", SFI_DEV_TYPE_IPC, 1, &pmic_gpio_platform_data}, {"watchdog_timer", SFI_DEV_TYPE_IPC, 1, &wdt_platform_data}, {"spi_opt_modem", SFI_DEV_TYPE_SPI, 0, &opt_modem_platform_data}, {"spi_emp_modem", SFI_DEV_TYPE_SPI, 0, &emp_modem_platform_data}, {"spi_ifx_modem", SFI_DEV_TYPE_SPI, 0, &ifx_mdm_platform_data, 1}, {"spi_6260_modem", SFI_DEV_TYPE_SPI, 0, &ifx_mdm_platform_data, 1}, {"spi_ifx_gps", SFI_DEV_TYPE_SPI, 0, &ifx_gps_platform_data}, {"cptm1217", SFI_DEV_TYPE_I2C, 0, &cp_tm1217_platform_data}, {"cy8ctma340", SFI_DEV_TYPE_I2C, 1, &cyttsp_platform_data}, {"spi_max3111", SFI_DEV_TYPE_SPI, 0, &max3111_platform_data}, {"i2c_max7315", SFI_DEV_TYPE_I2C, 1, &max7315_platform_data}, {"i2c_max7315_2", SFI_DEV_TYPE_I2C, 1, &max7315_platform_data}, {"i2c_thermal", SFI_DEV_TYPE_I2C, 0, &emc1403_platform_data}, {"i2c_accel", SFI_DEV_TYPE_I2C, 0, &lis331dl_platform_data}, {"lis3lv02d", SFI_DEV_TYPE_I2C, 0, &lis3dh_platform_data}, {"lis3dh_acc", SFI_DEV_TYPE_I2C, 0, &lis3dh_platform_data}, {"accel", SFI_DEV_TYPE_I2C, 0, &lis3dh_platform_data}, {"apds9802ps", SFI_DEV_TYPE_I2C, 0, &apds9802ps_platform_data}, {"apds9802als", SFI_DEV_TYPE_I2C, 0, &apds9802als_platform_data}, #ifdef CONFIG_SENSORS_HMC5883 {"hmc5883", SFI_DEV_TYPE_I2C, 1, &no_platform_data}, #endif {"cy8ctmg110", SFI_DEV_TYPE_I2C, 0, &cy8ctmg110_platform_data}, {"aava-max3107", SFI_DEV_TYPE_SPI, 1, &no_platform_data}, {"pmic_audio", SFI_DEV_TYPE_SPI, 1, &no_platform_data}, {"pmic_audio", SFI_DEV_TYPE_IPC, 1, &no_platform_data}, {"msic_audio", SFI_DEV_TYPE_SPI, 1, &audio_platform_data}, {"msic_audio", SFI_DEV_TYPE_IPC, 1, &audio_platform_data}, {"sst-platform", SFI_DEV_TYPE_IPC, 1, &no_platform_data}, {"sn95031", SFI_DEV_TYPE_IPC, 1, &no_platform_data}, {"msic_ocd", SFI_DEV_TYPE_IPC, 1, &msic_ocd_platform_data, 1}, #ifdef FIXME_MLD // just turn on the 1386 controller for dv0.9 {"mxt224", SFI_DEV_TYPE_I2C, 1, &atmel_mxt_platform_data_init}, #else {"mxt1386", SFI_DEV_TYPE_I2C, 1, &atmel_mxt_platform_data_init}, //运行这个 #endif {"i2c_TC35894-nEB1", SFI_DEV_TYPE_I2C, 0, &tc35894xbg_n_platform_data}, {"i2c_TC35894-i", SFI_DEV_TYPE_I2C, 0, &tc35894xbg_i_platform_data}, {"bh1770glc", SFI_DEV_TYPE_I2C, 0, &bh1770glc_platform_data_init}, {"qpdst900", SFI_DEV_TYPE_I2C, 1, &qpdst900_platform_data_init}, {"lp5523", SFI_DEV_TYPE_I2C, 0, &lp5523_platform_data_init}, {"bcm4751-gps", SFI_DEV_TYPE_I2C, 0, &bcm4751_platform_data }, {"pn544", SFI_DEV_TYPE_I2C, 0, &pn544_platform_data}, #ifdef CONFIG_A1026 {"audience_es305", SFI_DEV_TYPE_I2C, 0, &audience_platform_data}, #endif {"wl12xx_clk_vmmc", SFI_DEV_TYPE_SD, 0, &wl12xx_platform_data_init, 1}, {"l3g4200", SFI_DEV_TYPE_I2C, 1, &l3g4200_platform_data}, #ifdef CONFIG_INPUT_MPU3050 {"gyro", SFI_DEV_TYPE_I2C, 1, &mpu_platform_data}, //add for gyro #endif {"baro", SFI_DEV_TYPE_I2C, 1, &baro_platform_data}, //add for baro /* * I2C devices for camera image subsystem which will not be load into * I2C core while initialize */ {"dis71430m", SFI_DEV_TYPE_I2C, 0, &discam_platform_data_init}, {"ov2720", SFI_DEV_TYPE_I2C, 0, &ov2720_platform_data_init}, {"smiapp", SFI_DEV_TYPE_I2C, 0, &no_platform_data}, {"ad58xx", SFI_DEV_TYPE_I2C, 0, &no_platform_data}, {"as3645a", SFI_DEV_TYPE_I2C, 0, &as3645a_platform_data_init}, #ifdef CONFIG_SENSORS_SENSOR_HUB {"sensor_hub", SFI_DEV_TYPE_SPI, 0, &sensor_hub_platform_data}, #endif {"unipoint", SFI_DEV_TYPE_I2C, 0, &unipoint_platform_data}, {"lm3555", SFI_DEV_TYPE_I2C, 0, &no_platform_data}, {"lm3554", SFI_DEV_TYPE_I2C, 0, &no_platform_data}, {"msic_adc", SFI_DEV_TYPE_IPC, 1, &msic_adc_platform_data}, {"hsi_ifx_modem", SFI_DEV_TYPE_HSI, 0, &hsi_modem_platform_data}, #ifdef CONFIG_BATTERY_INTEL_MDF {"max17042_battery", SFI_DEV_TYPE_I2C, 1, &max17042_platform_data}, #endif {"mt9e013", SFI_DEV_TYPE_I2C, 0, &mt9e013_platform_data_init}, {"mt9m114", SFI_DEV_TYPE_I2C, 0, &mt9m114_platform_data_init}, {}, };
- atmel_mxt_platform_data_init 函数如下:
2243 static void *atmel_mxt_platform_data_init(void *info) 2244 { 2245 struct i2c_board_info *i2c_info = (struct i2c_board_info *) info; 2246 static struct mxt_platform_data mxt_platform_data; 2247 2248 printk(KERN_INFO "In %s.", __func__); 2249 2250 memset(&mxt_platform_data, 0x00, 2251 sizeof(struct mxt_platform_data)); 2252 2253 #ifdef FIXME_MLD 2254 mxt_platform_data.x_line = 18; 2255 mxt_platform_data.y_line = 11; 2256 #else 2257 mxt_platform_data.x_line = 28; //触摸屏的x长度 2258 mxt_platform_data.y_line = 41; //触摸屏的y长度 2259 #endif 2260 mxt_platform_data.x_size = 1024; 2261 mxt_platform_data.y_size = 1024; 2262 mxt_platform_data.num_touch = 10; 2263 mxt_platform_data.blen = 0; 2264 mxt_platform_data.threshold = 30; 2265 mxt_platform_data.orient = MXT_DIAGONAL_COUNTER; //触摸屏的方向 2266 mxt_platform_data.irqflags = IRQF_TRIGGER_FALLING; 2267 mxt_platform_data.voltage = 3000000; 2268 mxt_platform_data.init_platform_hw = &mxt_init_platform_hw; //调用这个函数 2269 2270 i2c_info->irq = 62 + MRST_IRQ_OFFSET; 2271 return &mxt_platform_data; 2272 2273 } 2189 /* Functions to init platform data for atmel_mxt_ts touch controller */ 2190 static int mxt_init_platform_hw(void) 2191 { 2192 int rc; 2193 int reset_gpio = 129; 2194 int int_gpio = 62; 2195 2196 printk(KERN_INFO "In %s.", __func__); 2197 2198 /* should get the GPIO's out of SFI */ 2199 2200 /* init interrupt gpio */ 2201 rc = gpio_request(int_gpio, NULL); 2202 if (rc < 0) { 2203 printk(KERN_ERR "mxt: request interrupt gpio failed."); 2204 goto err; 2205 } 2206 rc = gpio_direction_input(int_gpio); 2207 if (rc < 0) { 2208 printk(KERN_ERR "mxt: set direction of interrupt gpio failed."); 2209 gpio_free(int_gpio); 2210 goto err; 2211 } 2212 2213 /* init reset gpio */ 2214 rc = gpio_request(reset_gpio, NULL); 2215 if (rc < 0) { 2216 gpio_free(int_gpio); 2217 printk(KERN_ERR "mxt: request reset gpio failed."); 2218 goto err; 2219 } 2220 rc = gpio_direction_output(reset_gpio, 1); 2221 if (rc < 0) { 2222 printk(KERN_ERR "mxt: set direction of reset gpio failed."); 2223 gpio_free(int_gpio); 2224 gpio_free(reset_gpio); 2225 goto err; 2226 } 2227 2228 /* reset the chip */ 2229 gpio_set_value(reset_gpio, 1); 2230 mdelay(10); 2231 gpio_set_value(reset_gpio, 0); 2232 mdelay(10); 2233 gpio_set_value(reset_gpio, 1); 2234 mdelay(100); 2235 2236 printk(KERN_INFO "%s success", __func__); 2237 2238 return 0; 2239 err: 2240 return -1; 2241 }
- /include/linux/i2c/atmel_mxt_ts.h 中定义了 orient 的几种类型:
18 /* Orient */ 19 #define MXT_NORMAL 0x0 //正常模式 20 #define MXT_DIAGONAL 0x1 //对角线 21 #define MXT_HORIZONTAL_FLIP 0x2 22 #define MXT_ROTATED_90_COUNTER 0x3 23 #define MXT_VERTICAL_FLIP 0x4 24 #define MXT_ROTATED_90 0x5 25 #define MXT_ROTATED_180 0x6 26 #define MXT_DIAGONAL_COUNTER 0x7 //反对角线 27 28 /* The platform data for the Atmel maXTouch touchscreen driver */ 29 struct mxt_platform_data { 30 const u8 *config; 31 size_t config_length; 32 33 unsigned int x_line; 34 unsigned int y_line; 35 unsigned int x_size; 36 unsigned int y_size; 37 unsigned int blen; 38 unsigned int threshold; 39 unsigned int voltage; 40 unsigned char orient; 41 unsigned char num_touch; 42 unsigned long irqflags; 43 int (*init_platform_hw)(void); 44 }; 45
-
atmel_mxt_ts 本身的驱动位于 /drivers/input/touchscreen/atmel_mxt_ts.c 中