#include #include #include #include #include #include #include #define MODULE_NAME "ltc1695" #define MODULE_VERSION_STR "v1.0" static int speed = 100; module_param(speed, int, 0644); MODULE_PARM_DESC(speed, "Fan speed [0:100]%%. Default: 100"); static const unsigned short normal_i2c[] = { 0x74, I2C_CLIENT_END }; struct ltc1695_data { struct i2c_client *client; struct device *hwmon_dev; }; static int ltc1695_set_speed(struct i2c_client *client, u8 speed) { u8 cmd; if (speed > 100) { return -EINVAL; } cmd = 0x80 | ((0x3A * speed) / 100); return i2c_smbus_write_byte(client, cmd); } static ssize_t ltc1695_speed_show(struct device *dev, struct device_attribute *attr, char *buf) { return sprintf(buf, "%u\n", speed); } static ssize_t ltc1695_speed_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { ssize_t ret = -EINVAL; struct i2c_client *client = to_i2c_client(dev); unsigned long val = simple_strtoul(buf, NULL, 0); ret = ltc1695_set_speed(client, val); if (ret == 0) { speed = val; ret = size; } return ret; } static DEVICE_ATTR(speed, 0644, ltc1695_speed_show, ltc1695_speed_store); static int ltc1695_probe(struct i2c_client *client, const struct i2c_device_id *id) { int ret; struct ltc1695_data *data; if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { return -ENODEV; } ret = ltc1695_set_speed(client, speed); if (ret != 0) { goto error; } data = kzalloc(sizeof(struct ltc1695_data), GFP_KERNEL); if (data == NULL) { dev_err(&client->dev, "Failed to allocate device memory !\n"); return -ENOMEM; } i2c_set_clientdata(client, data); data->client = client; ret = device_create_file(&client->dev, &dev_attr_speed); if (ret != 0) { dev_err(&client->dev, "Failed to create sysfs hook !\n"); goto error_device_create_file; } /* Register sysfs hooks */ //err = sysfs_create_group(&client->dev.kobj, &g760a_group); //if (err) // goto error_sysfs_create_group; data->hwmon_dev = hwmon_device_register(&client->dev); if (IS_ERR(data->hwmon_dev)) { dev_err(&client->dev, "Failed to register HW monitor device\n" ); ret = PTR_ERR(data->hwmon_dev); goto error_hwmon_device_register; } dev_info(&client->dev, "Detected LTC1695 chip\n"); return 0; error_hwmon_device_register: //sysfs_remove_group(&client->dev.kobj, &g760a_group); device_remove_file(&client->dev, &dev_attr_speed); error_device_create_file: kfree(data); i2c_set_clientdata(client, NULL); error: dev_err(&client->dev, "Probe failed\n"); return ret; } static int ltc1695_remove(struct i2c_client *client) { struct ltc1695_data *data = i2c_get_clientdata(client); hwmon_device_unregister(data->hwmon_dev); device_remove_file(&client->dev, &dev_attr_speed); kfree(data); i2c_set_clientdata(client, NULL); return 0; } static const struct i2c_device_id ltc1695_id[] = { { MODULE_NAME, 0 }, { } }; MODULE_DEVICE_TABLE(i2c, ltc1695_id); static struct i2c_driver ltc1695_driver = { .driver = { .name = MODULE_NAME, }, .probe = ltc1695_probe, .remove = ltc1695_remove, .id_table = ltc1695_id, }; static int __init ltc1695_init(void) { return i2c_add_driver(<c1695_driver); } module_init(ltc1695_init); static void __exit ltc1695_exit(void) { i2c_del_driver(<c1695_driver); } module_exit(ltc1695_exit); MODULE_DESCRIPTION("sysmobts v1 FAN Driver"); MODULE_AUTHOR("Lyrtech RD Inc. "); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:" MODULE_NAME);