0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/export.h>
0009 #include <linux/interrupt.h>
0010 #include <linux/i2c.h>
0011 #include <linux/spi/spi.h>
0012 #include <linux/gpio/machine.h>
0013
0014 #include <linux/mfd/wm831x/irq.h>
0015 #include <linux/mfd/wm831x/gpio.h>
0016 #include <linux/mfd/wm8994/pdata.h>
0017 #include <linux/mfd/arizona/pdata.h>
0018
0019 #include <linux/regulator/machine.h>
0020
0021 #include <sound/wm0010.h>
0022 #include <sound/wm2200.h>
0023 #include <sound/wm5100.h>
0024 #include <sound/wm8996.h>
0025 #include <sound/wm8962.h>
0026 #include <sound/wm9081.h>
0027
0028 #include <linux/platform_data/spi-s3c64xx.h>
0029
0030 #include "cpu.h"
0031 #include "irqs.h"
0032
0033 #include "crag6410.h"
0034
0035 static struct wm0010_pdata wm0010_pdata = {
0036 .gpio_reset = S3C64XX_GPN(6),
0037 .reset_active_high = 1,
0038 };
0039
0040 static struct spi_board_info wm1253_devs[] = {
0041 [0] = {
0042 .modalias = "wm0010",
0043 .max_speed_hz = 26 * 1000 * 1000,
0044 .bus_num = 0,
0045 .chip_select = 0,
0046 .mode = SPI_MODE_0,
0047 .irq = S3C_EINT(4),
0048 .platform_data = &wm0010_pdata,
0049 },
0050 };
0051
0052 static struct spi_board_info balblair_devs[] = {
0053 [0] = {
0054 .modalias = "wm0010",
0055 .max_speed_hz = 26 * 1000 * 1000,
0056 .bus_num = 0,
0057 .chip_select = 0,
0058 .mode = SPI_MODE_0,
0059 .irq = S3C_EINT(4),
0060 .platform_data = &wm0010_pdata,
0061 },
0062 };
0063
0064 static struct wm5100_pdata wm5100_pdata = {
0065 .ldo_ena = S3C64XX_GPN(7),
0066 .irq_flags = IRQF_TRIGGER_HIGH,
0067 .gpio_base = CODEC_GPIO_BASE,
0068
0069 .in_mode = {
0070 WM5100_IN_DIFF,
0071 WM5100_IN_DIFF,
0072 WM5100_IN_DIFF,
0073 WM5100_IN_SE,
0074 },
0075
0076 .hp_pol = CODEC_GPIO_BASE + 3,
0077 .jack_modes = {
0078 { WM5100_MICDET_MICBIAS3, 0, 0 },
0079 { WM5100_MICDET_MICBIAS2, 1, 1 },
0080 },
0081
0082 .gpio_defaults = {
0083 0,
0084 0,
0085 0,
0086 0,
0087 0x2,
0088 0x3,
0089 },
0090 };
0091
0092 static struct wm8996_retune_mobile_config wm8996_retune[] = {
0093 {
0094 .name = "Sub LPF",
0095 .rate = 48000,
0096 .regs = {
0097 0x6318, 0x6300, 0x1000, 0x0000, 0x0004, 0x2000, 0xF000,
0098 0x0000, 0x0004, 0x2000, 0xF000, 0x0000, 0x0004, 0x2000,
0099 0xF000, 0x0000, 0x0004, 0x1000, 0x0800, 0x4000
0100 },
0101 },
0102 {
0103 .name = "Sub HPF",
0104 .rate = 48000,
0105 .regs = {
0106 0x000A, 0x6300, 0x1000, 0x0000, 0x0004, 0x2000, 0xF000,
0107 0x0000, 0x0004, 0x2000, 0xF000, 0x0000, 0x0004, 0x2000,
0108 0xF000, 0x0000, 0x0004, 0x1000, 0x0800, 0x4000
0109 },
0110 },
0111 };
0112
0113 static struct wm8996_pdata wm8996_pdata __initdata = {
0114 .ldo_ena = S3C64XX_GPN(7),
0115 .gpio_base = CODEC_GPIO_BASE,
0116 .micdet_def = 1,
0117 .inl_mode = WM8996_DIFFERRENTIAL_1,
0118 .inr_mode = WM8996_DIFFERRENTIAL_1,
0119
0120 .irq_flags = IRQF_TRIGGER_RISING,
0121
0122 .gpio_default = {
0123 0x8001,
0124 0x8001,
0125 0x0141,
0126 0x0002,
0127 0x020e,
0128 },
0129
0130 .retune_mobile_cfgs = wm8996_retune,
0131 .num_retune_mobile_cfgs = ARRAY_SIZE(wm8996_retune),
0132 };
0133
0134 static struct wm8962_pdata wm8962_pdata __initdata = {
0135 .gpio_init = {
0136 0,
0137 WM8962_GPIO_FN_OPCLK,
0138 WM8962_GPIO_FN_DMICCLK,
0139 0,
0140 0x8000 | WM8962_GPIO_FN_DMICDAT,
0141 WM8962_GPIO_FN_IRQ,
0142 },
0143 .in4_dc_measure = true,
0144 };
0145
0146 static struct wm9081_pdata wm9081_pdata __initdata = {
0147 .irq_high = false,
0148 .irq_cmos = false,
0149 };
0150
0151 static const struct i2c_board_info wm1254_devs[] = {
0152 { I2C_BOARD_INFO("wm8996", 0x1a),
0153 .platform_data = &wm8996_pdata,
0154 .irq = GLENFARCLAS_PMIC_IRQ_BASE + WM831X_IRQ_GPIO_2,
0155 },
0156 { I2C_BOARD_INFO("wm9081", 0x6c),
0157 .platform_data = &wm9081_pdata, },
0158 };
0159
0160 static const struct i2c_board_info wm1255_devs[] = {
0161 { I2C_BOARD_INFO("wm5100", 0x1a),
0162 .platform_data = &wm5100_pdata,
0163 .irq = GLENFARCLAS_PMIC_IRQ_BASE + WM831X_IRQ_GPIO_2,
0164 },
0165 { I2C_BOARD_INFO("wm9081", 0x6c),
0166 .platform_data = &wm9081_pdata, },
0167 };
0168
0169 static const struct i2c_board_info wm1259_devs[] = {
0170 { I2C_BOARD_INFO("wm8962", 0x1a),
0171 .platform_data = &wm8962_pdata,
0172 .irq = GLENFARCLAS_PMIC_IRQ_BASE + WM831X_IRQ_GPIO_2,
0173 },
0174 };
0175
0176 static struct regulator_init_data wm8994_ldo1 = {
0177 .supply_regulator = "WALLVDD",
0178 };
0179
0180 static struct regulator_init_data wm8994_ldo2 = {
0181 .supply_regulator = "WALLVDD",
0182 };
0183
0184 static struct wm8994_pdata wm8994_pdata = {
0185 .gpio_base = CODEC_GPIO_BASE,
0186 .micb2_delay = 150,
0187 .gpio_defaults = {
0188 0x3,
0189 },
0190 .ldo = {
0191 { .init_data = &wm8994_ldo1, },
0192 { .init_data = &wm8994_ldo2, },
0193 },
0194 };
0195
0196 static const struct i2c_board_info wm1277_devs[] = {
0197 { I2C_BOARD_INFO("wm8958", 0x1a),
0198 .platform_data = &wm8994_pdata,
0199 .irq = GLENFARCLAS_PMIC_IRQ_BASE + WM831X_IRQ_GPIO_2,
0200 .dev_name = "wm8958",
0201 },
0202 };
0203
0204 static struct gpiod_lookup_table wm8994_gpiod_table = {
0205 .dev_id = "i2c-wm8958",
0206 .table = {
0207 GPIO_LOOKUP("GPION", 6,
0208 "wlf,ldo1ena", GPIO_ACTIVE_HIGH),
0209 GPIO_LOOKUP("GPION", 4,
0210 "wlf,ldo2ena", GPIO_ACTIVE_HIGH),
0211 { },
0212 },
0213 };
0214
0215 static struct arizona_pdata wm5102_reva_pdata = {
0216 .gpio_base = CODEC_GPIO_BASE,
0217 .irq_flags = IRQF_TRIGGER_HIGH,
0218 .micd_pol_gpio = CODEC_GPIO_BASE + 4,
0219 .micd_rate = 6,
0220 .gpio_defaults = {
0221 [2] = 0x10000,
0222 [3] = 0x4,
0223 },
0224 };
0225
0226 static struct spi_board_info wm5102_reva_spi_devs[] = {
0227 [0] = {
0228 .modalias = "wm5102",
0229 .max_speed_hz = 10 * 1000 * 1000,
0230 .bus_num = 0,
0231 .chip_select = 1,
0232 .mode = SPI_MODE_0,
0233 .irq = GLENFARCLAS_PMIC_IRQ_BASE +
0234 WM831X_IRQ_GPIO_2,
0235 .platform_data = &wm5102_reva_pdata,
0236 },
0237 };
0238
0239 static struct gpiod_lookup_table wm5102_reva_gpiod_table = {
0240 .dev_id = "spi0.1",
0241 .table = {
0242 GPIO_LOOKUP("GPION", 7,
0243 "wlf,ldoena", GPIO_ACTIVE_HIGH),
0244 { },
0245 },
0246 };
0247
0248 static struct arizona_pdata wm5102_pdata = {
0249 .gpio_base = CODEC_GPIO_BASE,
0250 .irq_flags = IRQF_TRIGGER_HIGH,
0251 .micd_pol_gpio = CODEC_GPIO_BASE + 2,
0252 .gpio_defaults = {
0253 [2] = 0x10000,
0254 [3] = 0x4,
0255 },
0256 };
0257
0258 static struct spi_board_info wm5102_spi_devs[] = {
0259 [0] = {
0260 .modalias = "wm5102",
0261 .max_speed_hz = 10 * 1000 * 1000,
0262 .bus_num = 0,
0263 .chip_select = 1,
0264 .mode = SPI_MODE_0,
0265 .irq = GLENFARCLAS_PMIC_IRQ_BASE +
0266 WM831X_IRQ_GPIO_2,
0267 .platform_data = &wm5102_pdata,
0268 },
0269 };
0270
0271 static struct gpiod_lookup_table wm5102_gpiod_table = {
0272 .dev_id = "spi0.1",
0273 .table = {
0274 GPIO_LOOKUP("GPION", 7,
0275 "wlf,ldo1ena", GPIO_ACTIVE_HIGH),
0276 { },
0277 },
0278 };
0279
0280 static struct spi_board_info wm5110_spi_devs[] = {
0281 [0] = {
0282 .modalias = "wm5110",
0283 .max_speed_hz = 10 * 1000 * 1000,
0284 .bus_num = 0,
0285 .chip_select = 1,
0286 .mode = SPI_MODE_0,
0287 .irq = GLENFARCLAS_PMIC_IRQ_BASE +
0288 WM831X_IRQ_GPIO_2,
0289 .platform_data = &wm5102_reva_pdata,
0290 },
0291 };
0292
0293 static const struct i2c_board_info wm6230_i2c_devs[] = {
0294 { I2C_BOARD_INFO("wm9081", 0x6c),
0295 .platform_data = &wm9081_pdata, },
0296 };
0297
0298 static struct wm2200_pdata wm2200_pdata = {
0299 .ldo_ena = S3C64XX_GPN(7),
0300 .gpio_defaults = {
0301 [2] = 0x0005,
0302 },
0303 };
0304
0305 static const struct i2c_board_info wm2200_i2c[] = {
0306 { I2C_BOARD_INFO("wm2200", 0x3a),
0307 .platform_data = &wm2200_pdata, },
0308 };
0309
0310 static const struct {
0311 u8 id;
0312 u8 rev;
0313 const char *name;
0314 const struct i2c_board_info *i2c_devs;
0315 int num_i2c_devs;
0316 const struct spi_board_info *spi_devs;
0317 int num_spi_devs;
0318
0319 struct gpiod_lookup_table *gpiod_table;
0320 } gf_mods[] = {
0321 { .id = 0x01, .rev = 0xff, .name = "1250-EV1 Springbank" },
0322 { .id = 0x02, .rev = 0xff, .name = "1251-EV1 Jura" },
0323 { .id = 0x03, .rev = 0xff, .name = "1252-EV1 Glenlivet" },
0324 { .id = 0x06, .rev = 0xff, .name = "WM8997-6721-CS96-EV1 Lapraoig" },
0325 { .id = 0x07, .rev = 0xff, .name = "WM5110-6271 Deanston",
0326 .spi_devs = wm5110_spi_devs,
0327 .num_spi_devs = ARRAY_SIZE(wm5110_spi_devs) },
0328 { .id = 0x08, .rev = 0xff, .name = "WM8903-6102 Tamdhu" },
0329 { .id = 0x09, .rev = 0xff, .name = "WM1811A-6305 Adelphi" },
0330 { .id = 0x0a, .rev = 0xff, .name = "WM8996-6272 Blackadder" },
0331 { .id = 0x0b, .rev = 0xff, .name = "WM8994-6235 Benromach" },
0332 { .id = 0x11, .rev = 0xff, .name = "6249-EV2 Glenfarclas", },
0333 { .id = 0x14, .rev = 0xff, .name = "6271-EV1 Lochnagar" },
0334 { .id = 0x15, .rev = 0xff, .name = "6320-EV1 Bells",
0335 .i2c_devs = wm6230_i2c_devs,
0336 .num_i2c_devs = ARRAY_SIZE(wm6230_i2c_devs) },
0337 { .id = 0x21, .rev = 0xff, .name = "1275-EV1 Mortlach" },
0338 { .id = 0x25, .rev = 0xff, .name = "1274-EV1 Glencadam" },
0339 { .id = 0x31, .rev = 0xff, .name = "1253-EV1 Tomatin",
0340 .spi_devs = wm1253_devs, .num_spi_devs = ARRAY_SIZE(wm1253_devs) },
0341 { .id = 0x32, .rev = 0xff, .name = "XXXX-EV1 Caol Illa" },
0342 { .id = 0x33, .rev = 0xff, .name = "XXXX-EV1 Oban" },
0343 { .id = 0x34, .rev = 0xff, .name = "WM0010-6320-CS42 Balblair",
0344 .spi_devs = balblair_devs,
0345 .num_spi_devs = ARRAY_SIZE(balblair_devs) },
0346 { .id = 0x39, .rev = 0xff, .name = "1254-EV1 Dallas Dhu",
0347 .i2c_devs = wm1254_devs, .num_i2c_devs = ARRAY_SIZE(wm1254_devs) },
0348 { .id = 0x3a, .rev = 0xff, .name = "1259-EV1 Tobermory",
0349 .i2c_devs = wm1259_devs, .num_i2c_devs = ARRAY_SIZE(wm1259_devs) },
0350 { .id = 0x3b, .rev = 0xff, .name = "1255-EV1 Kilchoman",
0351 .i2c_devs = wm1255_devs, .num_i2c_devs = ARRAY_SIZE(wm1255_devs) },
0352 { .id = 0x3c, .rev = 0xff, .name = "1273-EV1 Longmorn" },
0353 { .id = 0x3d, .rev = 0xff, .name = "1277-EV1 Littlemill",
0354 .i2c_devs = wm1277_devs, .num_i2c_devs = ARRAY_SIZE(wm1277_devs),
0355 .gpiod_table = &wm8994_gpiod_table },
0356 { .id = 0x3e, .rev = 0, .name = "WM5102-6271-EV1-CS127 Amrut",
0357 .spi_devs = wm5102_reva_spi_devs,
0358 .num_spi_devs = ARRAY_SIZE(wm5102_reva_spi_devs),
0359 .gpiod_table = &wm5102_reva_gpiod_table },
0360 { .id = 0x3e, .rev = -1, .name = "WM5102-6271-EV1-CS127 Amrut",
0361 .spi_devs = wm5102_spi_devs,
0362 .num_spi_devs = ARRAY_SIZE(wm5102_spi_devs),
0363 .gpiod_table = &wm5102_gpiod_table },
0364 { .id = 0x3f, .rev = -1, .name = "WM2200-6271-CS90-M-REV1",
0365 .i2c_devs = wm2200_i2c, .num_i2c_devs = ARRAY_SIZE(wm2200_i2c) },
0366 };
0367
0368 static int wlf_gf_module_probe(struct i2c_client *i2c)
0369 {
0370 int ret, i, j, id, rev;
0371
0372 ret = i2c_smbus_read_byte_data(i2c, 0);
0373 if (ret < 0) {
0374 dev_err(&i2c->dev, "Failed to read ID: %d\n", ret);
0375 return ret;
0376 }
0377
0378 id = (ret & 0xfe) >> 2;
0379 rev = ret & 0x3;
0380 for (i = 0; i < ARRAY_SIZE(gf_mods); i++)
0381 if (id == gf_mods[i].id && (gf_mods[i].rev == 0xff ||
0382 rev == gf_mods[i].rev))
0383 break;
0384
0385 gpiod_add_lookup_table(&wm5102_reva_gpiod_table);
0386 gpiod_add_lookup_table(&wm5102_gpiod_table);
0387 gpiod_add_lookup_table(&wm8994_gpiod_table);
0388
0389 if (i < ARRAY_SIZE(gf_mods)) {
0390 dev_info(&i2c->dev, "%s revision %d\n",
0391 gf_mods[i].name, rev + 1);
0392
0393 for (j = 0; j < gf_mods[i].num_i2c_devs; j++) {
0394 if (IS_ERR(i2c_new_client_device(i2c->adapter,
0395 &(gf_mods[i].i2c_devs[j]))))
0396 dev_err(&i2c->dev, "Failed to register\n");
0397 }
0398
0399 spi_register_board_info(gf_mods[i].spi_devs,
0400 gf_mods[i].num_spi_devs);
0401
0402 if (gf_mods[i].gpiod_table)
0403 gpiod_add_lookup_table(gf_mods[i].gpiod_table);
0404 } else {
0405 dev_warn(&i2c->dev, "Unknown module ID 0x%x revision %d\n",
0406 id, rev + 1);
0407 }
0408
0409 return 0;
0410 }
0411
0412 static const struct i2c_device_id wlf_gf_module_id[] = {
0413 { "wlf-gf-module", 0 },
0414 { }
0415 };
0416
0417 static struct i2c_driver wlf_gf_module_driver = {
0418 .driver = {
0419 .name = "wlf-gf-module"
0420 },
0421 .probe_new = wlf_gf_module_probe,
0422 .id_table = wlf_gf_module_id,
0423 };
0424
0425 static int __init wlf_gf_module_register(void)
0426 {
0427 if (!soc_is_s3c64xx())
0428 return 0;
0429
0430 return i2c_add_driver(&wlf_gf_module_driver);
0431 }
0432 device_initcall(wlf_gf_module_register);