#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // codec init param #include "cx20810_config.h" #define I2C_CX20810_DRIVER_NAME "i2c_cx20810" #define MAX_CX20810_NUM (3) void netease_enable_clk(void); static int gpio_adc_rst = -1; // g_client_cx20810[0] is on adapter 0 and its address is 0x35 // g_client_cx20810[1] is on adapter 1 and its address is 0x35 // g_client_cx20810[2] is on adapter 1 and its address is 0x3B static struct i2c_client *g_client_cx20810[MAX_CX20810_NUM]; static const unsigned short i2c_cx20810_addr[] = {0x35, 0x3B, I2C_CLIENT_END}; static const struct i2c_device_id i2c_driver_cx20810_id[] = { {I2C_CX20810_DRIVER_NAME, 0}, {}}; // function declaration static int cx20810_hw_init(void); static int i2c_driver_cx20810_probe(struct i2c_client *client, const struct i2c_device_id *id); static int i2c_driver_cx20810_remove(struct i2c_client *client); static int i2c_driver_cx20810_detect(struct i2c_client *client, struct i2c_board_info *info); static int i2c_master_send_array_to_cx20810(const struct i2c_client *client, const char *buf, int length); static void cx20810_init(int index, int mode); int cx20810_set_mode(int mode, int index); // set cx20810 work mode int cx20810_set_mode(int mode, int index) { printk("Timothy:cx20810.c->cx20810_set_mode(), mode = %d, index = %d\n", mode, index); int i; int ret; char *param; int length; switch (mode) { case CX20810_NORMAL_MODE: param = codec_config_param_normal_mode; length = sizeof(codec_config_param_normal_mode); break; case CX20810_NORMAL_MODE_SIMPLE: param = codec_config_param_normal_mode_simple; length = sizeof(codec_config_param_normal_mode_simple); break; case CX20810_48K_16BIT_MODE: param = codec_config_param_48k_16bit_mode; length = sizeof(codec_config_param_48k_16bit_mode); break; case CX20810_96K_16BIT_MODE: param = codec_config_param_96k_16bit_mode; length = sizeof(codec_config_param_96k_16bit_mode); break; case CX20810_NIRMAL_MODE_CODEC3: param = codec3_config_param_normal_mode; length = sizeof(codec3_config_param_normal_mode); break; case CX20810_NIRMAL_MODE_CODEC3_SIMPLE: param = codec3_config_param_normal_mode_simple; length = sizeof(codec3_config_param_normal_mode_simple); break; default: return; break; } // if client is null, return if (g_client_cx20810[index] == NULL) { printk("Timothy:cx20810(%d) is not detected yet\n", index); return -1; } ret = i2c_master_send_array_to_cx20810(g_client_cx20810[index], param, length); if (ret != 0) { printk("Timothy:cx82011[%x] init error!\n", g_client_cx20810[index]->addr); return -1; } else { printk("Timothy:cx20810[%x] init ok\n", g_client_cx20810[index]->addr); return 0; } } EXPORT_SYMBOL(cx20810_set_mode); int cx20810_write_reg(int index, int addr, int regval) { char writedata[2] = {0}; if (index > 1) { return -1; } writedata[0] = (char)addr; writedata[1] = (char)regval; return i2c_master_send(g_client_cx20810[index], writedata, 2); } EXPORT_SYMBOL(cx20810_write_reg); int cx20810_read_reg(int index, int cmd, int *regval) { int error = 0; char data = 0; if (index > 1) { return -1; } error = i2c_master_send(g_client_cx20810[index], (const char *)&cmd, 1); // write reg addr if (1 != i2c_master_send(g_client_cx20810[index], (const char *)&cmd, 1)) { printk(KERN_ERR " cx20810_read_reg fail1! \n"); return -1; } // wait msleep(10); // read if (error >= 0) { error = i2c_master_recv(g_client_cx20810[index], &data, 1); if (error < 0) { printk(KERN_ERR " cx20810_read_reg fail2! \n"); } } else { printk(KERN_ERR " cx20810_read_reg fail1! \n"); } *regval = (int)data; return 0; } EXPORT_SYMBOL(cx20810_read_reg); // send parameters to cx20810 as master static int i2c_master_send_array_to_cx20810(const struct i2c_client *client, const char *buf, int length) { printk("Timothy:cx20810.c->i2c_master_send_array_to_cx20810()\n"); int i; int nwrite; for (i = 0; i < (length / 2); i++) { nwrite = i2c_master_send(client, buf + i * 2, 2); if (nwrite != 2) { printk("Timothy:send to cx20810 error\n"); return -1; } } return 0; } // initial cx20810 static void cx20810_init(int index, int mode) { printk("Timothy:cx20810.c->cx20810_init()\n"); if (cx20810_set_mode(mode, index) == 0) { printk("Timothy:cx20810 init success\n"); } else { printk("Timothy:cx20810 init fail\n"); } } static int i2c_driver_cx20810_probe(struct i2c_client *client, const struct i2c_device_id *id) { if (client->adapter->nr == 0 && client->addr == i2c_cx20810_addr[0]) { g_client_cx20810[1] = client; printk("Timothy:cx20810 (0x%x) init ok\n", client->addr); } else if (client->adapter->nr == 0 && client->addr == i2c_cx20810_addr[1]) { g_client_cx20810[0] = client; printk("Timothy:cx20810 (0x%x) init ok\n", client->addr); } return 0; } static int i2c_driver_cx20810_remove(struct i2c_client *client) { printk("Timothy:cx20810.c->i2c_driver_cx20810_remove()\n"); return 0; } MODULE_DEVICE_TABLE(i2c, i2c_driver_cx20810_id); static int i2c_driver_cx20810_detect(struct i2c_client *client, struct i2c_board_info *info) { printk("Timothy:cx20810.c->i2c_driver_cx20810_detect()...\n"); struct i2c_adapter *p_adapter; const char *type_name = I2C_CX20810_DRIVER_NAME; p_adapter = client->adapter; printk("Timothy:adapter->nr = %d\n", p_adapter->nr); if (0 == p_adapter->nr) { if (info->addr == i2c_cx20810_addr[0]) { printk("Timothy:detect cx20810 (%x) on i2c adapter (%d)\n", info->addr, p_adapter->nr); strlcpy(info->type, type_name, I2C_NAME_SIZE); return 0; } else if (info->addr == i2c_cx20810_addr[1]) { printk("Timothy:detect cx20810 (%x) on i2c adapter (%d)\n", info->addr, p_adapter->nr); strlcpy(info->type, type_name, I2C_NAME_SIZE); return 0; } } return ENODEV; } static struct i2c_driver i2c_driver_cx20810 = { .class = I2C_CLASS_HWMON, .probe = i2c_driver_cx20810_probe, .remove = i2c_driver_cx20810_remove, .id_table = i2c_driver_cx20810_id, .driver = { .name = I2C_CX20810_DRIVER_NAME, .owner = THIS_MODULE, }, .detect = i2c_driver_cx20810_detect, .address_list = i2c_cx20810_addr}; static int __init i2c_driver_cx20810_init(void) { printk("Timothy:cx20810.c->i2c_driver_cx20810_init()\n"); msleep(300); // cx20810_hw_init(); return i2c_add_driver(&i2c_driver_cx20810); } static void __exit i2c_driver_cx20810_exit(void) { printk("Timothy:cx20810.c->i2c_driver_cx20810_exit()\n"); i2c_del_driver(&i2c_driver_cx20810); } static int __init cpld_r311_probe(struct platform_device *pdev) { printk("Begin to set luyao asked gpios \n"); struct device_node *np = pdev->dev.of_node; struct device *dev = &pdev->dev; struct gpio_config cfg; int gpionum; gpionum = of_get_named_gpio_flags(np, "4v5_ldo_en", 0, (enum of_gpio_flags *)&cfg); if (gpio_is_valid(gpionum)) { gpio_request(gpionum, "4v5_ldo_en"); gpio_direction_output(gpionum, 1); printk("Set 4v5_ldo_en(%d) success\n", gpionum); } else { printk("Set 4v5_ldo_en fail\n"); } gpionum = of_get_named_gpio_flags(np, "3v_ldo_en", 0, (enum of_gpio_flags *)&cfg); if (gpio_is_valid(gpionum)) { gpio_request(gpionum, "3v_ldo_en"); gpio_direction_output(gpionum, 1); printk("Set 3v_ldo_en(%d) success\n", gpionum); } else { printk("Set 3v_ldo_en fail\n"); } gpionum = of_get_named_gpio_flags(np, "gp_adc_rst", 0, (enum of_gpio_flags *)&cfg); gpio_adc_rst = gpionum; if (!gpio_is_valid(gpionum)) { printk("get gp_adc_rst failed\n"); return -EINVAL; } else { printk("Get gp_adc_rst success,gpio:%d\n", gpionum); } devm_gpio_request(dev, gpionum, "gp_adc_rst"); gpio_direction_output(gpionum, 1); printk("Set gp_adc_rst(%d) to 1!\n", gpionum); return 0; } void netease_cpld_reset(void) { printk("Begin to reset cpld!\n"); if (gpio_is_valid(gpio_adc_rst)) { gpio_set_value(gpio_adc_rst, 0); msleep(100); printk("Begin to start cpld!\n"); gpio_set_value(gpio_adc_rst, 1); msleep(800); printk("Finish reseting cpld!\n"); } else { printk("Adc rst gpio is not init!\n"); } } static const struct of_device_id cpld_r311_ids[] = { {.compatible = "allwinner,cpld-r311-pv1"}, {/* Sentinel */}}; static struct platform_driver cpld_r311_driver = { .driver = { .owner = THIS_MODULE, .name = "cpld", .of_match_table = cpld_r311_ids, }, }; static int __init cpld_r311_init(void) { int ret = 0; #if 0 type = script_get_item("cpld", "gp_ldo_4_5", &item); if (SCIRPT_ITEM_VALUE_TYPE_PIO == type) { printk("luyao:set gp_ldo_4_5\n"); printk("Gpio:%d\n", item.gpio.gpio); gpio_request(item.gpio.gpio, NULL); gpio_direction_output(item.gpio.gpio, 1); gpio_set_value(item.gpio.gpio, 1); gpio_free(item.gpio.gpio); } type = script_get_item("cpld", "gp_ldo_3", &item); if (SCIRPT_ITEM_VALUE_TYPE_PIO == type) { printk("luyao:set gp_ldo_3\n"); printk("Gpio:%d\n", item.gpio.gpio); gpio_request(item.gpio.gpio, NULL); gpio_direction_output(item.gpio.gpio, 1); gpio_set_value(item.gpio.gpio, 1); gpio_free(item.gpio.gpio); } #endif printk("Begin to init cpld r311 driver!!\n"); ret = platform_driver_probe(&cpld_r311_driver, cpld_r311_probe); printk("platform_driver_probe:%d!\n", ret); return ret; } static void __exit cpld_r311_deinit(void) {} fs_initcall_sync(cpld_r311_init); module_exit(cpld_r311_deinit); late_initcall_sync(i2c_driver_cx20810_init); module_exit(i2c_driver_cx20810_exit); MODULE_AUTHOR("Timothy"); MODULE_DESCRIPTION("I2C device cx20810 loader"); MODULE_LICENSE("GPL");