* [RESEND PATCH 1/4] kernel.h: add find_closest() macro
2015-02-24 17:48 [RESEND PATCH 0/4] find_closest() macro Bartosz Golaszewski
@ 2015-02-24 17:48 ` Bartosz Golaszewski
2015-02-24 17:48 ` [RESEND PATCH 2/4] hwmon: (ina2xx) replace ina226_avg_bits() with find_closest() Bartosz Golaszewski
` (2 subsequent siblings)
3 siblings, 0 replies; 6+ messages in thread
From: Bartosz Golaszewski @ 2015-02-24 17:48 UTC (permalink / raw)
To: LKML; +Cc: Guenter Roeck, Jean Delvare, lm-sensors, Bartosz Golaszewski
Searching for the member of an array closest to 'x' is
duplicated in several places.
Add two macros that implement this algorithm for arrays
sorted both in ascending and descending order.
Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
---
include/linux/kernel.h | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index d6d630d..f4294da 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -116,6 +116,29 @@
} \
)
+#define __find_closest(x, a, as, op)( \
+{ \
+ typeof(as) _i, _as = (as) - 1; \
+ typeof(x) _x = (x); \
+ typeof(*a) *_a = (a); \
+ for (_i = 0; _i < _as; _i++) { \
+ if (_x op DIV_ROUND_CLOSEST(_a[_i] + _a[_i + 1], 2)) \
+ break; \
+ } \
+ (_i); \
+} \
+)
+
+/*
+ * Given an array 'a' (sorted in ascending order) of size 'as' return
+ * the index of the element in that array closest to 'x'.
+ */
+#define find_closest(x, a, as) __find_closest(x, a, as, <=)
+/*
+ * Similar to find_closest(), but 'a' is expected to be sorted
+ * in descending order.
+ */
+#define find_closest_desc(x, a, as) __find_closest(x, a, as, >)
#define _RET_IP_ (unsigned long)__builtin_return_address(0)
#define _THIS_IP_ ({ __label__ __here; __here: (unsigned long)&&__here; })
--
2.1.4
^ permalink raw reply [flat|nested] 6+ messages in thread
* [RESEND PATCH 2/4] hwmon: (ina2xx) replace ina226_avg_bits() with find_closest()
2015-02-24 17:48 [RESEND PATCH 0/4] find_closest() macro Bartosz Golaszewski
2015-02-24 17:48 ` [RESEND PATCH 1/4] kernel.h: add " Bartosz Golaszewski
@ 2015-02-24 17:48 ` Bartosz Golaszewski
2015-02-24 17:48 ` [RESEND PATCH 3/4] hwmon: (lm85) replace x_TO_REG() functions " Bartosz Golaszewski
2015-02-24 17:48 ` [RESEND PATCH 4/4] hwmon: (w83795) use find_closest_desc() in pwm_freq_to_reg() Bartosz Golaszewski
3 siblings, 0 replies; 6+ messages in thread
From: Bartosz Golaszewski @ 2015-02-24 17:48 UTC (permalink / raw)
To: LKML; +Cc: Guenter Roeck, Jean Delvare, lm-sensors, Bartosz Golaszewski
Use find_closest() to locate the closest average in ina226_avg_tab.
Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
---
drivers/hwmon/ina2xx.c | 16 ++--------------
1 file changed, 2 insertions(+), 14 deletions(-)
diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c
index d1542b7..fc7f023 100644
--- a/drivers/hwmon/ina2xx.c
+++ b/drivers/hwmon/ina2xx.c
@@ -141,19 +141,6 @@ static const struct ina2xx_config ina2xx_config[] = {
*/
static const int ina226_avg_tab[] = { 1, 4, 16, 64, 128, 256, 512, 1024 };
-static int ina226_avg_bits(int avg)
-{
- int i;
-
- /* Get the closest average from the tab. */
- for (i = 0; i < ARRAY_SIZE(ina226_avg_tab) - 1; i++) {
- if (avg <= (ina226_avg_tab[i] + ina226_avg_tab[i + 1]) / 2)
- break;
- }
-
- return i; /* Return 0b0111 for values greater than 1024. */
-}
-
static int ina226_reg_to_interval(u16 config)
{
int avg = ina226_avg_tab[INA226_READ_AVG(config)];
@@ -171,7 +158,8 @@ static u16 ina226_interval_to_reg(int interval, u16 config)
avg = DIV_ROUND_CLOSEST(interval * 1000,
INA226_TOTAL_CONV_TIME_DEFAULT);
- avg_bits = ina226_avg_bits(avg);
+ avg_bits = find_closest(avg, ina226_avg_tab,
+ ARRAY_SIZE(ina226_avg_tab));
return (config & ~INA226_AVG_RD_MASK) | INA226_SHIFT_AVG(avg_bits);
}
--
2.1.4
^ permalink raw reply [flat|nested] 6+ messages in thread
* [RESEND PATCH 3/4] hwmon: (lm85) replace x_TO_REG() functions with find_closest()
2015-02-24 17:48 [RESEND PATCH 0/4] find_closest() macro Bartosz Golaszewski
2015-02-24 17:48 ` [RESEND PATCH 1/4] kernel.h: add " Bartosz Golaszewski
2015-02-24 17:48 ` [RESEND PATCH 2/4] hwmon: (ina2xx) replace ina226_avg_bits() with find_closest() Bartosz Golaszewski
@ 2015-02-24 17:48 ` Bartosz Golaszewski
2015-02-24 21:04 ` Guenter Roeck
2015-02-24 17:48 ` [RESEND PATCH 4/4] hwmon: (w83795) use find_closest_desc() in pwm_freq_to_reg() Bartosz Golaszewski
3 siblings, 1 reply; 6+ messages in thread
From: Bartosz Golaszewski @ 2015-02-24 17:48 UTC (permalink / raw)
To: LKML; +Cc: Guenter Roeck, Jean Delvare, lm-sensors, Bartosz Golaszewski
Replace RANGE_TO_REG() and FREQ_TO_REG() functions with calls
to find_closest().
Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
---
drivers/hwmon/lm85.c | 43 ++++++++++++-------------------------------
1 file changed, 12 insertions(+), 31 deletions(-)
diff --git a/drivers/hwmon/lm85.c b/drivers/hwmon/lm85.c
index 2b4b419..4e81c99 100644
--- a/drivers/hwmon/lm85.c
+++ b/drivers/hwmon/lm85.c
@@ -188,18 +188,6 @@ static const int lm85_range_map[] = {
13300, 16000, 20000, 26600, 32000, 40000, 53300, 80000
};
-static int RANGE_TO_REG(long range)
-{
- int i;
-
- /* Find the closest match */
- for (i = 0; i < 15; ++i) {
- if (range <= (lm85_range_map[i] + lm85_range_map[i + 1]) / 2)
- break;
- }
-
- return i;
-}
#define RANGE_FROM_REG(val) lm85_range_map[(val) & 0x0f]
/* These are the PWM frequency encodings */
@@ -209,17 +197,7 @@ static const int lm85_freq_map[8] = { /* 1 Hz */
static const int adm1027_freq_map[8] = { /* 1 Hz */
11, 15, 22, 29, 35, 44, 59, 88
};
-
-static int FREQ_TO_REG(const int *map, unsigned long freq)
-{
- int i;
-
- /* Find the closest match */
- for (i = 0; i < 7; ++i)
- if (freq <= (map[i] + map[i + 1]) / 2)
- break;
- return i;
-}
+#define FREQ_MAP_SIZE 8
static int FREQ_FROM_REG(const int *map, u8 reg)
{
@@ -828,7 +806,8 @@ static ssize_t set_pwm_freq(struct device *dev,
data->cfg5 &= ~ADT7468_HFPWM;
lm85_write_value(client, ADT7468_REG_CFG5, data->cfg5);
} else { /* Low freq. mode */
- data->pwm_freq[nr] = FREQ_TO_REG(data->freq_map, val);
+ data->pwm_freq[nr] = find_closest(val, data->freq_map,
+ FREQ_MAP_SIZE - 1);
lm85_write_value(client, LM85_REG_AFAN_RANGE(nr),
(data->zone[nr].range << 4)
| data->pwm_freq[nr]);
@@ -1186,7 +1165,7 @@ static ssize_t set_temp_auto_temp_min(struct device *dev,
int nr = to_sensor_dev_attr(attr)->index;
struct lm85_data *data = dev_get_drvdata(dev);
struct i2c_client *client = data->client;
- long val;
+ long val, range;
int err;
err = kstrtol(buf, 10, &val);
@@ -1198,10 +1177,12 @@ static ssize_t set_temp_auto_temp_min(struct device *dev,
lm85_write_value(client, LM85_REG_AFAN_LIMIT(nr),
data->zone[nr].limit);
-/* Update temp_auto_max and temp_auto_range */
- data->zone[nr].range = RANGE_TO_REG(
- TEMP_FROM_REG(data->zone[nr].max_desired) -
- TEMP_FROM_REG(data->zone[nr].limit));
+ /* Update temp_auto_max and temp_auto_range */
+ range = TEMP_FROM_REG(data->zone[nr].max_desired) -
+ TEMP_FROM_REG(data->zone[nr].limit);
+ data->zone[nr].range = find_closest(range, lm85_range_map,
+ ARRAY_SIZE(lm85_range_map));
+
lm85_write_value(client, LM85_REG_AFAN_RANGE(nr),
((data->zone[nr].range & 0x0f) << 4)
| (data->pwm_freq[nr] & 0x07));
@@ -1236,8 +1217,8 @@ static ssize_t set_temp_auto_temp_max(struct device *dev,
mutex_lock(&data->update_lock);
min = TEMP_FROM_REG(data->zone[nr].limit);
data->zone[nr].max_desired = TEMP_TO_REG(val);
- data->zone[nr].range = RANGE_TO_REG(
- val - min);
+ data->zone[nr].range = find_closest(val - min, lm85_range_map,
+ ARRAY_SIZE(lm85_range_map));
lm85_write_value(client, LM85_REG_AFAN_RANGE(nr),
((data->zone[nr].range & 0x0f) << 4)
| (data->pwm_freq[nr] & 0x07));
--
2.1.4
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [RESEND PATCH 3/4] hwmon: (lm85) replace x_TO_REG() functions with find_closest()
2015-02-24 17:48 ` [RESEND PATCH 3/4] hwmon: (lm85) replace x_TO_REG() functions " Bartosz Golaszewski
@ 2015-02-24 21:04 ` Guenter Roeck
0 siblings, 0 replies; 6+ messages in thread
From: Guenter Roeck @ 2015-02-24 21:04 UTC (permalink / raw)
To: Bartosz Golaszewski; +Cc: LKML, Jean Delvare, lm-sensors
On Tue, Feb 24, 2015 at 06:48:28PM +0100, Bartosz Golaszewski wrote:
> Replace RANGE_TO_REG() and FREQ_TO_REG() functions with calls
> to find_closest().
>
> Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
> ---
> drivers/hwmon/lm85.c | 43 ++++++++++++-------------------------------
> 1 file changed, 12 insertions(+), 31 deletions(-)
>
> diff --git a/drivers/hwmon/lm85.c b/drivers/hwmon/lm85.c
> index 2b4b419..4e81c99 100644
> --- a/drivers/hwmon/lm85.c
> +++ b/drivers/hwmon/lm85.c
> @@ -188,18 +188,6 @@ static const int lm85_range_map[] = {
> 13300, 16000, 20000, 26600, 32000, 40000, 53300, 80000
> };
>
> -static int RANGE_TO_REG(long range)
> -{
> - int i;
> -
> - /* Find the closest match */
> - for (i = 0; i < 15; ++i) {
> - if (range <= (lm85_range_map[i] + lm85_range_map[i + 1]) / 2)
> - break;
> - }
> -
> - return i;
> -}
> #define RANGE_FROM_REG(val) lm85_range_map[(val) & 0x0f]
>
> /* These are the PWM frequency encodings */
> @@ -209,17 +197,7 @@ static const int lm85_freq_map[8] = { /* 1 Hz */
> static const int adm1027_freq_map[8] = { /* 1 Hz */
> 11, 15, 22, 29, 35, 44, 59, 88
> };
> -
> -static int FREQ_TO_REG(const int *map, unsigned long freq)
> -{
> - int i;
> -
> - /* Find the closest match */
> - for (i = 0; i < 7; ++i)
> - if (freq <= (map[i] + map[i + 1]) / 2)
> - break;
> - return i;
> -}
> +#define FREQ_MAP_SIZE 8
If you declare this as a constant, that constant should also be used
to declare the actual arrays.
>
> static int FREQ_FROM_REG(const int *map, u8 reg)
> {
> @@ -828,7 +806,8 @@ static ssize_t set_pwm_freq(struct device *dev,
> data->cfg5 &= ~ADT7468_HFPWM;
> lm85_write_value(client, ADT7468_REG_CFG5, data->cfg5);
> } else { /* Low freq. mode */
> - data->pwm_freq[nr] = FREQ_TO_REG(data->freq_map, val);
> + data->pwm_freq[nr] = find_closest(val, data->freq_map,
> + FREQ_MAP_SIZE - 1);
Why -1 ?
> lm85_write_value(client, LM85_REG_AFAN_RANGE(nr),
> (data->zone[nr].range << 4)
> | data->pwm_freq[nr]);
> @@ -1186,7 +1165,7 @@ static ssize_t set_temp_auto_temp_min(struct device *dev,
> int nr = to_sensor_dev_attr(attr)->index;
> struct lm85_data *data = dev_get_drvdata(dev);
> struct i2c_client *client = data->client;
> - long val;
> + long val, range;
> int err;
>
> err = kstrtol(buf, 10, &val);
> @@ -1198,10 +1177,12 @@ static ssize_t set_temp_auto_temp_min(struct device *dev,
> lm85_write_value(client, LM85_REG_AFAN_LIMIT(nr),
> data->zone[nr].limit);
>
> -/* Update temp_auto_max and temp_auto_range */
> - data->zone[nr].range = RANGE_TO_REG(
> - TEMP_FROM_REG(data->zone[nr].max_desired) -
> - TEMP_FROM_REG(data->zone[nr].limit));
> + /* Update temp_auto_max and temp_auto_range */
> + range = TEMP_FROM_REG(data->zone[nr].max_desired) -
> + TEMP_FROM_REG(data->zone[nr].limit);
> + data->zone[nr].range = find_closest(range, lm85_range_map,
> + ARRAY_SIZE(lm85_range_map));
> +
Is that really less complex than before ? Also, I wonder if it creates
more or less code. Can you provide code size comparisons ?
Thanks,
Guenter
^ permalink raw reply [flat|nested] 6+ messages in thread
* [RESEND PATCH 4/4] hwmon: (w83795) use find_closest_desc() in pwm_freq_to_reg()
2015-02-24 17:48 [RESEND PATCH 0/4] find_closest() macro Bartosz Golaszewski
` (2 preceding siblings ...)
2015-02-24 17:48 ` [RESEND PATCH 3/4] hwmon: (lm85) replace x_TO_REG() functions " Bartosz Golaszewski
@ 2015-02-24 17:48 ` Bartosz Golaszewski
3 siblings, 0 replies; 6+ messages in thread
From: Bartosz Golaszewski @ 2015-02-24 17:48 UTC (permalink / raw)
To: LKML; +Cc: Guenter Roeck, Jean Delvare, lm-sensors, Bartosz Golaszewski
Replace the loop iterating over pwm_freq_cksel0 with a call to
find_closest_desc().
Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
---
drivers/hwmon/w83795.c | 7 ++-----
1 file changed, 2 insertions(+), 5 deletions(-)
diff --git a/drivers/hwmon/w83795.c b/drivers/hwmon/w83795.c
index 2189413..1f0b301 100644
--- a/drivers/hwmon/w83795.c
+++ b/drivers/hwmon/w83795.c
@@ -308,11 +308,8 @@ static u8 pwm_freq_to_reg(unsigned long val, u16 clkin)
unsigned long best0, best1;
/* Best fit for cksel = 0 */
- for (reg0 = 0; reg0 < ARRAY_SIZE(pwm_freq_cksel0) - 1; reg0++) {
- if (val > (pwm_freq_cksel0[reg0] +
- pwm_freq_cksel0[reg0 + 1]) / 2)
- break;
- }
+ reg0 = find_closest_desc(val, pwm_freq_cksel0,
+ ARRAY_SIZE(pwm_freq_cksel0));
if (val < 375) /* cksel = 1 can't beat this */
return reg0;
best0 = pwm_freq_cksel0[reg0];
--
2.1.4
^ permalink raw reply [flat|nested] 6+ messages in thread